From d8ef5f69915c2941a88f58dbe0a0b6eb53d67346 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 5 Nov 2019 12:57:34 -0700 Subject: [PATCH 001/577] added internal fix dummy command to enable more control of fix ordering --- src/GRANULAR/pair_gran_hooke_history.cpp | 25 +++++++-- src/GRANULAR/pair_gran_hooke_history.h | 1 + src/GRANULAR/pair_granular.cpp | 41 ++++++++++----- src/GRANULAR/pair_granular.h | 3 +- src/USER-BOCS/fix_bocs.cpp | 4 +- src/USER-MISC/fix_srp.cpp | 17 ++++--- src/USER-MISC/pair_srp.cpp | 13 +++-- src/fix.cpp | 1 + src/fix.h | 1 + src/fix_balance.cpp | 1 + src/fix_deform.cpp | 1 + src/fix_dummy.cpp | 65 ++++++++++++++++++++++++ src/fix_dummy.h | 53 +++++++++++++++++++ src/fix_neigh_history.cpp | 14 +++++ src/fix_nh.cpp | 4 +- src/modify.cpp | 40 +++++++++++++++ src/modify.h | 1 + 17 files changed, 253 insertions(+), 32 deletions(-) create mode 100644 src/fix_dummy.cpp create mode 100644 src/fix_dummy.h diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index de205dce91..3375d9a7a3 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -24,6 +24,7 @@ #include "update.h" #include "modify.h" #include "fix.h" +#include "fix_dummy.h" #include "fix_neigh_history.h" #include "comm.h" #include "neighbor.h" @@ -43,7 +44,6 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) no_virial_fdotr_compute = 1; history = 1; size_history = 3; - fix_history = NULL; single_extra = 10; svector = new double[10]; @@ -60,6 +60,19 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) // keep default behavior of history[i][j] = -history[j][i] nondefault_history_transfer = 0; + + // create dummy fix as placeholder for FixNeighHistory + // this is so final order of Modify:fix will conform to input script + + fix_history = NULL; + + char **fixarg = new char*[3]; + fixarg[0] = (char *) "NEIGH_HISTORY_DUMMY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "DUMMY"; + modify->add_fix(3,fixarg,1); + delete [] fixarg; + fix_dummy = (FixDummy *) modify->fix[modify->nfix-1]; } /* ---------------------------------------------------------------------- */ @@ -69,7 +82,9 @@ PairGranHookeHistory::~PairGranHookeHistory() if (copymode) return; delete [] svector; - if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (!fix_history) modify->delete_fix("NEIGH_HISTORY_DUMMY"); + else modify->delete_fix("NEIGH_HISTORY"); if (allocated) { memory->destroy(setflag); @@ -412,7 +427,9 @@ void PairGranHookeHistory::init_style() dt = update->dt; - // if first init, create Fix needed for storing shear history + // if history is stored and first init, create Fix to store history + // it replaces FixDummy, created in the constructor + // this is so its order in the fix list is preserved if (history && fix_history == NULL) { char dnumstr[16]; @@ -422,7 +439,7 @@ void PairGranHookeHistory::init_style() fixarg[1] = (char *) "all"; fixarg[2] = (char *) "NEIGH_HISTORY"; fixarg[3] = dnumstr; - modify->add_fix(4,fixarg,1); + modify->replace_fix("NEIGH_HISTORY_DUMMY",4,fixarg,1); delete [] fixarg; fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; fix_history->pair = this; diff --git a/src/GRANULAR/pair_gran_hooke_history.h b/src/GRANULAR/pair_gran_hooke_history.h index 81f2d8fd4a..309af54ee6 100644 --- a/src/GRANULAR/pair_gran_hooke_history.h +++ b/src/GRANULAR/pair_gran_hooke_history.h @@ -56,6 +56,7 @@ class PairGranHookeHistory : public Pair { int size_history; + class FixDummy *fix_dummy; class FixNeighHistory *fix_history; // storage of rigid body masses for use in granular interactions diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 85eab1fb9e..d37ae8c00c 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -1,13 +1,14 @@ /* ---------------------------------------------------------------------- -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. ------------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- @@ -25,6 +26,7 @@ See the README file in the top-level LAMMPS directory. #include "update.h" #include "modify.h" #include "fix.h" +#include "fix_dummy.h" #include "fix_neigh_history.h" #include "comm.h" #include "neighbor.h" @@ -62,7 +64,6 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) { single_enable = 1; no_virial_fdotr_compute = 1; - fix_history = NULL; single_extra = 12; svector = new double[single_extra]; @@ -90,6 +91,19 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) nondefault_history_transfer = 0; tangential_history_index = 0; roll_history_index = twist_history_index = 0; + + // create dummy fix as placeholder for FixNeighHistory + // this is so final order of Modify:fix will conform to input script + + fix_history = NULL; + + char **fixarg = new char*[3]; + fixarg[0] = (char *) "NEIGH_HISTORY_DUMMY"; + fixarg[1] = (char *) "all"; + fixarg[2] = (char *) "DUMMY"; + modify->add_fix(3,fixarg,1); + delete [] fixarg; + fix_dummy = (FixDummy *) modify->fix[modify->nfix-1]; } /* ---------------------------------------------------------------------- */ @@ -97,7 +111,9 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) PairGranular::~PairGranular() { delete [] svector; - if (fix_history) modify->delete_fix("NEIGH_HISTORY"); + + if (!fix_history) modify->delete_fix("NEIGH_HISTORY_DUMMY"); + else modify->delete_fix("NEIGH_HISTORY"); if (allocated) { memory->destroy(setflag); @@ -1021,8 +1037,9 @@ void PairGranular::init_style() dt = update->dt; - // if history is stored: - // if first init, create Fix needed for storing history + // if history is stored and first init, create Fix to store history + // it replaces FixDummy, created in the constructor + // this is so its order in the fix list is preserved if (use_history && fix_history == NULL) { char dnumstr[16]; @@ -1032,7 +1049,7 @@ void PairGranular::init_style() fixarg[1] = (char *) "all"; fixarg[2] = (char *) "NEIGH_HISTORY"; fixarg[3] = dnumstr; - modify->add_fix(4,fixarg,1); + modify->replace_fix("NEIGH_HISTORY_DUMMY",4,fixarg,1); delete [] fixarg; fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; fix_history->pair = this; diff --git a/src/GRANULAR/pair_granular.h b/src/GRANULAR/pair_granular.h index d799acb733..e9ba629b49 100644 --- a/src/GRANULAR/pair_granular.h +++ b/src/GRANULAR/pair_granular.h @@ -51,6 +51,7 @@ class PairGranular : public Pair { double *maxrad_dynamic,*maxrad_frozen; double **cut; + class FixDummy *fix_dummy; class FixNeighHistory *fix_history; // storage of rigid body masses for use in granular interactions @@ -111,4 +112,4 @@ 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/USER-BOCS/fix_bocs.cpp b/src/USER-BOCS/fix_bocs.cpp index adce231bf1..0c5ebb7df4 100644 --- a/src/USER-BOCS/fix_bocs.cpp +++ b/src/USER-BOCS/fix_bocs.cpp @@ -302,10 +302,10 @@ FixBocs::FixBocs(LAMMPS *lmp, int narg, char **arg) : // pre_exchange only required if flips can occur due to shape changes if (flipflag && (p_flag[3] || p_flag[4] || p_flag[5])) - pre_exchange_flag = 1; + pre_exchange_flag = pre_exchange_migrate = 1; if (flipflag && (domain->yz != 0.0 || domain->xz != 0.0 || domain->xy != 0.0)) - pre_exchange_flag = 1; + pre_exchange_flag = pre_exchange_migrate = 1; } // convert input periods to frequencies diff --git a/src/USER-MISC/fix_srp.cpp b/src/USER-MISC/fix_srp.cpp index c0db252db4..2a96555fd7 100644 --- a/src/USER-MISC/fix_srp.cpp +++ b/src/USER-MISC/fix_srp.cpp @@ -22,6 +22,7 @@ #include "atom.h" #include "force.h" #include "domain.h" +#include "modify.h" #include "comm.h" #include "memory.h" #include "error.h" @@ -112,19 +113,21 @@ void FixSRP::init() if ((bptype < 1) || (bptype > atom->ntypes)) error->all(FLERR,"Illegal bond particle type"); - // fix SRP should be the first fix running at the PRE_EXCHANGE step. - // Otherwise it might conflict with, e.g. fix deform + // this fix must come before any fix which migrates atoms in its pre_exchange() + // b/c this fix's pre_exchange() creates per-atom data structure + // that data must be current for atom migration to carry it along - if (modify->n_pre_exchange > 1) { - char *first = modify->fix[modify->list_pre_exchange[0]]->id; - if ((comm->me == 0) && (strcmp(id,first) != 0)) - error->warning(FLERR,"Internal fix for pair srp defined too late." - " May lead to incorrect behavior."); + for (int i = 0; i < modify->nfix; i++) { + if (modify->fix[i] == this) break; + if (modify->fix[i]->pre_exchange_migrate) + error->all(FLERR,"Fix SRP comes after a fix which " + "migrates atoms in pre_exchange"); } // setup neigh exclusions for diff atom types // bond particles do not interact with other types // type bptype only interacts with itself + char* arg1[4]; arg1[0] = (char *) "exclude"; arg1[1] = (char *) "type"; diff --git a/src/USER-MISC/pair_srp.cpp b/src/USER-MISC/pair_srp.cpp index 606fdc9fc5..d0e73b265d 100644 --- a/src/USER-MISC/pair_srp.cpp +++ b/src/USER-MISC/pair_srp.cpp @@ -79,13 +79,18 @@ PairSRP::PairSRP(LAMMPS *lmp) : Pair(lmp) segment = NULL; // generate unique fix-id for this pair style instance + fix_id = strdup("XX_FIX_SRP"); fix_id[0] = '0' + srp_instance / 10; fix_id[1] = '0' + srp_instance % 10; ++srp_instance; - // create fix SRP instance here, as it has to - // be executed before all other fixes + // create fix SRP instance here + // similar to granular pair styles with history, + // this should be early enough that FixSRP::pre_exchange() + // will be invoked before other fixes that migrate atoms + // this is checked for in FixSRP + char **fixarg = new char*[3]; fixarg[0] = fix_id; fixarg[1] = (char *) "all"; @@ -143,7 +148,6 @@ PairSRP::~PairSRP() ------------------------------------------------------------------------- */ void PairSRP::compute(int eflag, int vflag) - { // setup energy and virial ev_init(eflag, vflag); @@ -458,6 +462,7 @@ void PairSRP::init_style() error->all(FLERR,"PairSRP: Pair srp requires newton pair on"); // verify that fix SRP is still defined and has not been changed. + int ifix = modify->find_fix(fix_id); if (f_srp != (FixSRP *)modify->fix[ifix]) error->all(FLERR,"Fix SRP has been changed unexpectedly"); @@ -471,6 +476,7 @@ void PairSRP::init_style() // bonds of this type will be represented by bond particles // if bond type is 0, then all bonds have bond particles // btype = bond type + char c0[20]; char* arg0[2]; sprintf(c0, "%d", btype); @@ -506,7 +512,6 @@ void PairSRP::init_style() double PairSRP::init_one(int i, int j) { - if (setflag[i][j] == 0) error->all(FLERR,"PairSRP: All pair coeffs are not set"); cut[j][i] = cut[i][j]; diff --git a/src/fix.cpp b/src/fix.cpp index d86acf0ae4..024d44e5bd 100644 --- a/src/fix.cpp +++ b/src/fix.cpp @@ -79,6 +79,7 @@ Fix::Fix(LAMMPS *lmp, int /*narg*/, char **arg) : respa_level = -1; maxexchange = 0; maxexchange_dynamic = 0; + pre_exchange_migrate = 0; scalar_flag = vector_flag = array_flag = 0; peratom_flag = local_flag = 0; diff --git a/src/fix.h b/src/fix.h index bcab6f289e..fa016232f0 100644 --- a/src/fix.h +++ b/src/fix.h @@ -58,6 +58,7 @@ class Fix : protected Pointers { int respa_level; // which respa level to apply fix (1-Nrespa) int maxexchange; // max # of per-atom values for Comm::exchange() int maxexchange_dynamic; // 1 if fix sets maxexchange dynamically + int pre_exchange_migrate; // 1 if fix migrates atoms in pre_exchange() int scalar_flag; // 0/1 if compute_scalar() function exists int vector_flag; // 0/1 if compute_vector() function exists diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 5ca1ec124a..46525796a7 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -40,6 +40,7 @@ FixBalance::FixBalance(LAMMPS *lmp, int narg, char **arg) : if (narg < 6) error->all(FLERR,"Illegal fix balance command"); box_change_domain = 1; + pre_exchange_migrate = 1; scalar_flag = 1; extscalar = 0; vector_flag = 1; diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 9d84c4bb62..7b3239f1af 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -48,6 +48,7 @@ rfix(NULL), irregular(NULL), set(NULL) no_change_box = 1; restart_global = 1; + pre_exchange_migrate = 1; nevery = force->inumeric(FLERR,arg[3]); if (nevery <= 0) error->all(FLERR,"Illegal fix deform command"); diff --git a/src/fix_dummy.cpp b/src/fix_dummy.cpp new file mode 100644 index 0000000000..fd9d0cf062 --- /dev/null +++ b/src/fix_dummy.cpp @@ -0,0 +1,65 @@ +/* ---------------------------------------------------------------------- + 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_dummy.h" +#include +#include "error.h" + +using namespace LAMMPS_NS; +using namespace FixConst; + +/* ---------------------------------------------------------------------- */ + +FixDummy::FixDummy(LAMMPS *lmp, int narg, char **arg) : + Fix(lmp, narg, arg) +{ + // process optional args + // customize here and in setmask() by adding a new keyword from fix.h + // only necessary if both of these are true: + // (a) the real fix you are placeholding for defines the method + // (b) the real fix will be defined so late in run initialization + // that the dummy fix will have already been processed by Modify::init() + // to add its index to its lists of fixes to invoke during timestepping + + initial_integrate_flag = final_integrate_flag = 0; + pre_exchange_flag = pre_neighbor_flag = 0; + pre_force_flag = post_force_flag = 0; + end_of_step_flag = 0; + + int iarg = 3; + while (iarg < narg) { + if (strcmp(arg[iarg],"initial_integrate") == 0) initial_integrate_flag = 1; + else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; + else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; + else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; + else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; + else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; + else error->all(FLERR,"Illegal fix DUMMY command"); + iarg++; + } +} + +/* ---------------------------------------------------------------------- */ + +int FixDummy::setmask() +{ + int mask = 0; + if (initial_integrate_flag) mask |= INITIAL_INTEGRATE; + if (final_integrate_flag) mask |= FINAL_INTEGRATE; + if (pre_exchange_flag) mask |= PRE_EXCHANGE; + if (pre_neighbor_flag) mask |= PRE_NEIGHBOR; + if (pre_force_flag) mask |= PRE_FORCE; + if (post_force_flag) mask |= POST_FORCE; + if (end_of_step_flag) mask |= END_OF_STEP; + return mask; +} diff --git a/src/fix_dummy.h b/src/fix_dummy.h new file mode 100644 index 0000000000..ea8ce97c3a --- /dev/null +++ b/src/fix_dummy.h @@ -0,0 +1,53 @@ +/* -*- 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(DUMMY,FixDummy) + +#else + +#ifndef LMP_FIX_DUMMY_H +#define LMP_FIX_DUMMY_H + +#include "fix.h" + +namespace LAMMPS_NS { + +class FixDummy : public Fix { + public: + FixDummy(class LAMMPS *, int, char **); + virtual ~FixDummy() {} + int setmask(); + + protected: + int initial_integrate_flag,final_integrate_flag; + int pre_exchange_flag,pre_neighbor_flag; + int pre_force_flag,post_force_flag; + int end_of_step_flag; +}; + +} + +#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/fix_neigh_history.cpp b/src/fix_neigh_history.cpp index 673e2b1c06..1967e43336 100644 --- a/src/fix_neigh_history.cpp +++ b/src/fix_neigh_history.cpp @@ -19,6 +19,7 @@ #include "comm.h" #include "neighbor.h" #include "neigh_list.h" +#include "modify.h" #include "force.h" #include "pair.h" #include "memory.h" @@ -147,6 +148,19 @@ void FixNeighHistory::init() if (atom->tag_enable == 0) error->all(FLERR,"Neighbor history requires atoms have IDs"); + // this fix must come before any fix which migrates atoms in its pre_exchange() + // b/c this fix's pre_exchange() creates per-atom data structure + // that data must be current for atom migration to carry it along + + for (int i = 0; i < modify->nfix; i++) { + if (modify->fix[i] == this) break; + if (modify->fix[i]->pre_exchange_migrate) + error->all(FLERR,"Fix neigh_history comes after a fix which " + "migrates atoms in pre_exchange"); + } + + // setup data struct + allocate_pages(); } diff --git a/src/fix_nh.cpp b/src/fix_nh.cpp index bb3fe7559c..3098a8c72c 100644 --- a/src/fix_nh.cpp +++ b/src/fix_nh.cpp @@ -492,10 +492,10 @@ FixNH::FixNH(LAMMPS *lmp, int narg, char **arg) : // pre_exchange only required if flips can occur due to shape changes if (flipflag && (p_flag[3] || p_flag[4] || p_flag[5])) - pre_exchange_flag = 1; + pre_exchange_flag = pre_exchange_migrate = 1; if (flipflag && (domain->yz != 0.0 || domain->xz != 0.0 || domain->xy != 0.0)) - pre_exchange_flag = 1; + pre_exchange_flag = pre_exchange_migrate = 1; } // convert input periods to frequencies diff --git a/src/modify.cpp b/src/modify.cpp index 101540f786..732770f34e 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -953,6 +953,46 @@ void Modify::add_fix(int narg, char **arg, int trysuffix) fix[ifix]->post_constructor(); } +/* ---------------------------------------------------------------------- + replace replaceID fix with a new fix + this is used by callers to preserve ordering of fixes + e.g. create replaceID as a FixDummy instance early in the input script + replace it later with the desired Fix instance +------------------------------------------------------------------------- */ + +void Modify::replace_fix(const char *replaceID, + int narg, char **arg, int trysuffix) +{ + int ifix = find_fix(replaceID); + if (ifix < 0) error->all(FLERR,"Modify replace_fix ID could not be found"); + + // change ID, igroup, style of fix being replaced to match new fix + // requires some error checking on arguments for new fix + + if (narg < 3) error->all(FLERR,"Illegal replace_fix invocation"); + int jfix = find_fix(arg[0]); + if (jfix >= 0) error->all(FLERR,"Replace_fix ID is already in use"); + + delete [] fix[ifix]->id; + int n = strlen(arg[0]) + 1; + fix[ifix]->id = new char[n]; + strcpy(fix[ifix]->id,arg[0]); + + int jgroup = group->find(arg[1]); + if (jgroup == -1) error->all(FLERR,"Could not find replace_fix group ID"); + fix[ifix]->igroup = jgroup; + + delete [] fix[ifix]->style; + n = strlen(arg[2]) + 1; + fix[ifix]->style = new char[n]; + strcpy(fix[ifix]->style,arg[2]); + + // invoke add_fix + // it will find and overwrite the replaceID fix + + add_fix(narg,arg,trysuffix); +} + /* ---------------------------------------------------------------------- one instance per fix in style_fix.h ------------------------------------------------------------------------- */ diff --git a/src/modify.h b/src/modify.h index b736485196..0b809d4d6a 100644 --- a/src/modify.h +++ b/src/modify.h @@ -96,6 +96,7 @@ class Modify : protected Pointers { virtual int min_reset_ref(); void add_fix(int, char **, int trysuffix=1); + void replace_fix(const char *, int, char **, int trysuffix=1); void modify_fix(int, char **); void delete_fix(const char *); void delete_fix(int); -- GitLab From ca0cf23a4b56e62965c9eec8858b60d88578d7ef Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 5 Nov 2019 16:59:44 -0700 Subject: [PATCH 002/577] fix a bug with indexing the replaced fix and optional args --- src/GRANULAR/pair_gran_hooke_history.cpp | 3 ++- src/GRANULAR/pair_granular.cpp | 3 ++- src/fix_dummy.cpp | 11 ++++++----- 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 3375d9a7a3..3c27b9f423 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -441,7 +441,8 @@ void PairGranHookeHistory::init_style() fixarg[3] = dnumstr; modify->replace_fix("NEIGH_HISTORY_DUMMY",4,fixarg,1); delete [] fixarg; - fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + int ifix = modify->find_fix("NEIGH_HISTORY"); + fix_history = (FixNeighHistory *) modify->fix[modify->ifix]; fix_history->pair = this; } diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index d37ae8c00c..27547fff91 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -1051,7 +1051,8 @@ void PairGranular::init_style() fixarg[3] = dnumstr; modify->replace_fix("NEIGH_HISTORY_DUMMY",4,fixarg,1); delete [] fixarg; - fix_history = (FixNeighHistory *) modify->fix[modify->nfix-1]; + int ifix = modify->find_fix("NEIGH_HISTORY"); + fix_history = (FixNeighHistory *) modify->fix[modify->ifix]; fix_history->pair = this; } diff --git a/src/fix_dummy.cpp b/src/fix_dummy.cpp index fd9d0cf062..a08ac187ba 100644 --- a/src/fix_dummy.cpp +++ b/src/fix_dummy.cpp @@ -29,7 +29,7 @@ FixDummy::FixDummy(LAMMPS *lmp, int narg, char **arg) : // (a) the real fix you are placeholding for defines the method // (b) the real fix will be defined so late in run initialization // that the dummy fix will have already been processed by Modify::init() - // to add its index to its lists of fixes to invoke during timestepping + // so its index needs to be added to lists of fixes invoked during a run initial_integrate_flag = final_integrate_flag = 0; pre_exchange_flag = pre_neighbor_flag = 0; @@ -40,10 +40,11 @@ FixDummy::FixDummy(LAMMPS *lmp, int narg, char **arg) : while (iarg < narg) { if (strcmp(arg[iarg],"initial_integrate") == 0) initial_integrate_flag = 1; else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; - else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; - else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; - else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; - else if (strcmp(arg[iarg],"final_integrate") == 0) final_integrate_flag = 1; + else if (strcmp(arg[iarg],"pre_exchange") == 0) pre_exchange_flag = 1; + else if (strcmp(arg[iarg],"pre_neighbor") == 0) pre_neighbor_flag = 1; + else if (strcmp(arg[iarg],"pre_force") == 0) pre_force_flag = 1; + else if (strcmp(arg[iarg],"post_force") == 0) post_force_flag = 1; + else if (strcmp(arg[iarg],"end_of_step") == 0) end_of_step_flag = 1; else error->all(FLERR,"Illegal fix DUMMY command"); iarg++; } -- GitLab From 09e539cce198db21068db9a0023316b11b18dae6 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 6 Nov 2019 08:35:31 -0700 Subject: [PATCH 003/577] make IDs of 2 fix neigh history instances unique --- src/GRANULAR/pair_gran_hooke_history.cpp | 14 +++++++------- src/GRANULAR/pair_granular.cpp | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 3c27b9f423..87bc49e332 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -67,7 +67,7 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) fix_history = NULL; char **fixarg = new char*[3]; - fixarg[0] = (char *) "NEIGH_HISTORY_DUMMY"; + fixarg[0] = (char *) "NEIGH_HISTORY_HOOKE_HERTZ_DUMMY"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "DUMMY"; modify->add_fix(3,fixarg,1); @@ -83,8 +83,8 @@ PairGranHookeHistory::~PairGranHookeHistory() delete [] svector; - if (!fix_history) modify->delete_fix("NEIGH_HISTORY_DUMMY"); - else modify->delete_fix("NEIGH_HISTORY"); + if (!fix_history) modify->delete_fix("NEIGH_HISTORY_HOOKE_HERTZ_DUMMY"); + else modify->delete_fix("NEIGH_HISTORY_HOOKE_HERTZ"); if (allocated) { memory->destroy(setflag); @@ -435,13 +435,13 @@ void PairGranHookeHistory::init_style() char dnumstr[16]; sprintf(dnumstr,"%d",size_history); char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[0] = (char *) "NEIGH_HISTORY_HOOKE_HERTZ"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "NEIGH_HISTORY"; fixarg[3] = dnumstr; - modify->replace_fix("NEIGH_HISTORY_DUMMY",4,fixarg,1); + modify->replace_fix("NEIGH_HISTORY_HOOKE_HERTZ_DUMMY",4,fixarg,1); delete [] fixarg; - int ifix = modify->find_fix("NEIGH_HISTORY"); + int ifix = modify->find_fix("NEIGH_HISTORY_HOOKE_HERTZ"); fix_history = (FixNeighHistory *) modify->fix[modify->ifix]; fix_history->pair = this; } @@ -509,7 +509,7 @@ void PairGranHookeHistory::init_style() // set fix which stores history info if (history) { - int ifix = modify->find_fix("NEIGH_HISTORY"); + int ifix = modify->find_fix("NEIGH_HISTORY_HOOKE_HERTZ"); if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); fix_history = (FixNeighHistory *) modify->fix[ifix]; } diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 27547fff91..1fe0950986 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -98,7 +98,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) fix_history = NULL; char **fixarg = new char*[3]; - fixarg[0] = (char *) "NEIGH_HISTORY_DUMMY"; + fixarg[0] = (char *) "NEIGH_HISTORY_GRANULAR_DUMMY"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "DUMMY"; modify->add_fix(3,fixarg,1); @@ -112,8 +112,8 @@ PairGranular::~PairGranular() { delete [] svector; - if (!fix_history) modify->delete_fix("NEIGH_HISTORY_DUMMY"); - else modify->delete_fix("NEIGH_HISTORY"); + if (!fix_history) modify->delete_fix("NEIGH_HISTORY_GRANULAR_DUMMY"); + else modify->delete_fix("NEIGH_HISTORY_GRANULAR"); if (allocated) { memory->destroy(setflag); @@ -1045,13 +1045,13 @@ void PairGranular::init_style() char dnumstr[16]; sprintf(dnumstr,"%d",size_history); char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY"; + fixarg[0] = (char *) "NEIGH_HISTORY_GRANULAR"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "NEIGH_HISTORY"; fixarg[3] = dnumstr; - modify->replace_fix("NEIGH_HISTORY_DUMMY",4,fixarg,1); + modify->replace_fix("NEIGH_HISTORY_GRANULAR_DUMMY",4,fixarg,1); delete [] fixarg; - int ifix = modify->find_fix("NEIGH_HISTORY"); + int ifix = modify->find_fix("NEIGH_HISTORY_GRANULAR"); fix_history = (FixNeighHistory *) modify->fix[modify->ifix]; fix_history->pair = this; } @@ -1122,7 +1122,7 @@ void PairGranular::init_style() // set fix which stores history info if (size_history > 0) { - int ifix = modify->find_fix("NEIGH_HISTORY"); + int ifix = modify->find_fix("NEIGH_HISTORY_GRANULAR"); if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); fix_history = (FixNeighHistory *) modify->fix[ifix]; } -- GitLab From d34502669c69992ebaccff5ab427db93d6b334cd Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 6 Nov 2019 09:38:38 -0700 Subject: [PATCH 004/577] fixed a typo --- src/GRANULAR/pair_gran_hooke_history.cpp | 18 +++++++++--------- src/GRANULAR/pair_granular.cpp | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 87bc49e332..0c88dd8eed 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -67,12 +67,12 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) fix_history = NULL; char **fixarg = new char*[3]; - fixarg[0] = (char *) "NEIGH_HISTORY_HOOKE_HERTZ_DUMMY"; + fixarg[0] = (char *) "NEIGH_HISTORY_HH_DUMMY"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "DUMMY"; modify->add_fix(3,fixarg,1); delete [] fixarg; - fix_dummy = (FixDummy *) modify->fix[modify->nfix-1]; + fix_dummy = (FixDummy *) modify->fix[nfix-1]; } /* ---------------------------------------------------------------------- */ @@ -83,8 +83,8 @@ PairGranHookeHistory::~PairGranHookeHistory() delete [] svector; - if (!fix_history) modify->delete_fix("NEIGH_HISTORY_HOOKE_HERTZ_DUMMY"); - else modify->delete_fix("NEIGH_HISTORY_HOOKE_HERTZ"); + if (!fix_history) modify->delete_fix("NEIGH_HISTORY_HH_DUMMY"); + else modify->delete_fix("NEIGH_HISTORY_HH"); if (allocated) { memory->destroy(setflag); @@ -435,14 +435,14 @@ void PairGranHookeHistory::init_style() char dnumstr[16]; sprintf(dnumstr,"%d",size_history); char **fixarg = new char*[4]; - fixarg[0] = (char *) "NEIGH_HISTORY_HOOKE_HERTZ"; + fixarg[0] = (char *) "NEIGH_HISTORY_HH"; fixarg[1] = (char *) "all"; fixarg[2] = (char *) "NEIGH_HISTORY"; fixarg[3] = dnumstr; - modify->replace_fix("NEIGH_HISTORY_HOOKE_HERTZ_DUMMY",4,fixarg,1); + modify->replace_fix("NEIGH_HISTORY_HH_DUMMY",4,fixarg,1); delete [] fixarg; - int ifix = modify->find_fix("NEIGH_HISTORY_HOOKE_HERTZ"); - fix_history = (FixNeighHistory *) modify->fix[modify->ifix]; + int ifix = modify->find_fix("NEIGH_HISTORY_HH"); + fix_history = (FixNeighHistory *) modify->fix[ifix]; fix_history->pair = this; } @@ -509,7 +509,7 @@ void PairGranHookeHistory::init_style() // set fix which stores history info if (history) { - int ifix = modify->find_fix("NEIGH_HISTORY_HOOKE_HERTZ"); + int ifix = modify->find_fix("NEIGH_HISTORY_HH"); if (ifix < 0) error->all(FLERR,"Could not find pair fix neigh history ID"); fix_history = (FixNeighHistory *) modify->fix[ifix]; } diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index 1fe0950986..ba7a3bce50 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -103,7 +103,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) fixarg[2] = (char *) "DUMMY"; modify->add_fix(3,fixarg,1); delete [] fixarg; - fix_dummy = (FixDummy *) modify->fix[modify->nfix-1]; + fix_dummy = (FixDummy *) modify->fix[nfix-1]; } /* ---------------------------------------------------------------------- */ @@ -1052,7 +1052,7 @@ void PairGranular::init_style() modify->replace_fix("NEIGH_HISTORY_GRANULAR_DUMMY",4,fixarg,1); delete [] fixarg; int ifix = modify->find_fix("NEIGH_HISTORY_GRANULAR"); - fix_history = (FixNeighHistory *) modify->fix[modify->ifix]; + fix_history = (FixNeighHistory *) modify->fix[ifix]; fix_history->pair = this; } -- GitLab From 6af726e58968ae2bd9baca795d868a17ad4b9543 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 6 Nov 2019 10:26:13 -0700 Subject: [PATCH 005/577] undo a re-bug change - sigh --- src/GRANULAR/pair_gran_hooke_history.cpp | 2 +- src/GRANULAR/pair_granular.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/GRANULAR/pair_gran_hooke_history.cpp b/src/GRANULAR/pair_gran_hooke_history.cpp index 0c88dd8eed..29ca53d361 100644 --- a/src/GRANULAR/pair_gran_hooke_history.cpp +++ b/src/GRANULAR/pair_gran_hooke_history.cpp @@ -72,7 +72,7 @@ PairGranHookeHistory::PairGranHookeHistory(LAMMPS *lmp) : Pair(lmp) fixarg[2] = (char *) "DUMMY"; modify->add_fix(3,fixarg,1); delete [] fixarg; - fix_dummy = (FixDummy *) modify->fix[nfix-1]; + fix_dummy = (FixDummy *) modify->fix[modify->nfix-1]; } /* ---------------------------------------------------------------------- */ diff --git a/src/GRANULAR/pair_granular.cpp b/src/GRANULAR/pair_granular.cpp index ba7a3bce50..fef8ded5f7 100644 --- a/src/GRANULAR/pair_granular.cpp +++ b/src/GRANULAR/pair_granular.cpp @@ -103,7 +103,7 @@ PairGranular::PairGranular(LAMMPS *lmp) : Pair(lmp) fixarg[2] = (char *) "DUMMY"; modify->add_fix(3,fixarg,1); delete [] fixarg; - fix_dummy = (FixDummy *) modify->fix[nfix-1]; + fix_dummy = (FixDummy *) modify->fix[modify->nfix-1]; } /* ---------------------------------------------------------------------- */ -- GitLab From 3736af0aaf5f1522e1e48ceb5fceeaada30cb3e2 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 26 Nov 2019 13:42:32 -0700 Subject: [PATCH 006/577] initial refactoring on AtomVec class --- src/DIPOLE/atom_vec_dipole.cpp | 884 +---------- src/DIPOLE/atom_vec_dipole.h | 45 - src/MOLECULE/atom_vec_angle.cpp | 940 ++---------- src/MOLECULE/atom_vec_angle.h | 53 +- src/MOLECULE/atom_vec_bond.cpp | 855 +---------- src/MOLECULE/atom_vec_bond.h | 47 +- src/MOLECULE/atom_vec_full.cpp | 1171 ++------------- src/MOLECULE/atom_vec_full.h | 60 +- src/MOLECULE/atom_vec_molecular.cpp | 1151 ++------------- src/MOLECULE/atom_vec_molecular.h | 56 +- src/MOLECULE/atom_vec_template.cpp | 804 +--------- src/MOLECULE/atom_vec_template.h | 50 +- src/PERI/atom_vec_peri.cpp | 899 +----------- src/PERI/atom_vec_peri.h | 48 - src/SPIN/atom_vec_spin.cpp | 924 +----------- src/SPIN/atom_vec_spin.h | 54 - src/atom.cpp | 220 ++- src/atom.h | 146 +- src/atom_vec.cpp | 2112 ++++++++++++++++++++++++++- src/atom_vec.h | 159 +- src/atom_vec_atomic.cpp | 677 +-------- src/atom_vec_atomic.h | 40 +- src/atom_vec_charge.cpp | 762 +--------- src/atom_vec_charge.h | 45 - src/atom_vec_sphere.cpp | 1153 +-------------- src/atom_vec_sphere.h | 52 - 26 files changed, 3151 insertions(+), 10256 deletions(-) diff --git a/src/DIPOLE/atom_vec_dipole.cpp b/src/DIPOLE/atom_vec_dipole.cpp index 0b6a27888f..dc3279227d 100644 --- a/src/DIPOLE/atom_vec_dipole.cpp +++ b/src/DIPOLE/atom_vec_dipole.cpp @@ -31,880 +31,40 @@ AtomVecDipole::AtomVecDipole(LAMMPS *lmp) : AtomVec(lmp) molecular = 0; mass_type = 1; - comm_x_only = 0; - comm_f_only = 1; - size_forward = 6; - size_reverse = 3; - size_border = 11; - size_velocity = 3; - size_data_atom = 9; - size_data_vel = 4; - xcol_data = 4; - atom->q_flag = atom->mu_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecDipole::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - q = memory->grow(atom->q,nmax,"atom:q"); - mu = memory->grow(atom->mu,nmax,4,"atom:mu"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecDipole::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - q = atom->q; mu = atom->mu; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecDipole::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - q[j] = q[i]; - mu[j][0] = mu[i][0]; - mu[j][1] = mu[i][1]; - mu[j][2] = mu[i][2]; - mu[j][3] = mu[i][3]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDipole::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - mu[i][0] = buf[m++]; - mu[i][1] = buf[m++]; - mu[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDipole::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - mu[i][0] = buf[m++]; - mu[i][1] = buf[m++]; - mu[i][2] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - mu[i][0] = buf[m++]; - mu[i][1] = buf[m++]; - mu[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDipole::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = mu[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = mu[j][3]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = mu[j][3]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = mu[j][3]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = mu[j][3]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = q[j]; - buf[m++] = mu[j][0]; - buf[m++] = mu[j][1]; - buf[m++] = mu[j][2]; - buf[m++] = mu[j][3]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDipole::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - mu[i][0] = buf[m++]; - mu[i][1] = buf[m++]; - mu[i][2] = buf[m++]; - mu[i][3] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDipole::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - mu[i][0] = buf[m++]; - mu[i][1] = buf[m++]; - mu[i][2] = buf[m++]; - mu[i][3] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file -/* ---------------------------------------------------------------------- */ + fields_grow = (char *) "q mu"; + fields_copy = (char *) "q mu"; + fields_comm = (char *) "mu3"; + fields_comm_vel = (char *) "mu3"; + fields_reverse = NULL; + fields_border = (char *) "q mu"; + fields_border_vel = (char *) "q mu"; + fields_exchange = (char *) "q mu"; + fields_restart = (char *) "q mu"; + fields_create = (char *) "q mu"; + fields_data_atom = (char *) "id type q x mu3"; + fields_data_vel = NULL; -int AtomVecDipole::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - q[i] = buf[m++]; - mu[i][0] = buf[m++]; - mu[i][1] = buf[m++]; - mu[i][2] = buf[m++]; - mu[i][3] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack all atom quantities for shipping to another proc - xyz must be 1st 3 values, so that comm::exchange can test on them -------------------------------------------------------------------------- */ - -int AtomVecDipole::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = q[i]; - buf[m++] = mu[i][0]; - buf[m++] = mu[i][1]; - buf[m++] = mu[i][2]; - buf[m++] = mu[i][3]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDipole::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - q[nlocal] = buf[m++]; - mu[nlocal][0] = buf[m++]; - mu[nlocal][1] = buf[m++]; - mu[nlocal][2] = buf[m++]; - mu[nlocal][3] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecDipole::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 16 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecDipole::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = q[i]; - buf[m++] = mu[i][0]; - buf[m++] = mu[i][1]; - buf[m++] = mu[i][2]; - buf[m++] = mu[i][3]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecDipole::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - q[nlocal] = buf[m++]; - mu[nlocal][0] = buf[m++]; - mu[nlocal][1] = buf[m++]; - mu[nlocal][2] = buf[m++]; - mu[nlocal][3] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecDipole::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - q[nlocal] = 0.0; - mu[nlocal][0] = 0.0; - mu[nlocal][1] = 0.0; - mu[nlocal][2] = 0.0; - mu[nlocal][3] = 0.0; - - atom->nlocal++; + setup_fields(); } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what the default AtomVec::data_atom() just initialized ------------------------------------------------------------------------- */ void AtomVecDipole::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - q[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - mu[nlocal][0] = utils::numeric(FLERR,values[6],true,lmp); - mu[nlocal][1] = utils::numeric(FLERR,values[7],true,lmp); - mu[nlocal][2] = utils::numeric(FLERR,values[8],true,lmp); - mu[nlocal][3] = sqrt(mu[nlocal][0]*mu[nlocal][0] + - mu[nlocal][1]*mu[nlocal][1] + - mu[nlocal][2]*mu[nlocal][2]); - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecDipole::data_atom_hybrid(int nlocal, char **values) -{ - q[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - mu[nlocal][0] = utils::numeric(FLERR,values[1],true,lmp); - mu[nlocal][1] = utils::numeric(FLERR,values[2],true,lmp); - mu[nlocal][2] = utils::numeric(FLERR,values[3],true,lmp); - mu[nlocal][3] = sqrt(mu[nlocal][0]*mu[nlocal][0] + - mu[nlocal][1]*mu[nlocal][1] + - mu[nlocal][2]*mu[nlocal][2]); - return 4; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecDipole::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = q[i]; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = mu[i][0]; - buf[i][7] = mu[i][1]; - buf[i][8] = mu[i][2]; - buf[i][9] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][11] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecDipole::pack_data_hybrid(int i, double *buf) -{ - buf[0] = q[i]; - buf[1] = mu[i][0]; - buf[2] = mu[i][1]; - buf[3] = mu[i][2]; - return 4; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecDipole::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT \ - " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e " - "%-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4], - buf[i][5],buf[i][6],buf[i][7],buf[i][8], - (int) ubuf(buf[i][9]).i,(int) ubuf(buf[i][10]).i, - (int) ubuf(buf[i][11]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ + AtomVec::data_atom(coord,imagetmp,values); -int AtomVecDipole::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2],buf[3]); - return 4; + int ilocal = atom->nlocal-1; + double mu = atom->mu[ilocal]; + mu[3] = sqrt(mu[0]*mu[0] + mu[1]*mu[1] + mu[2]*mu[2]); } -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecDipole::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("q")) bytes += memory->usage(q,nmax); - if (atom->memcheck("mu")) bytes += memory->usage(mu,nmax,4); - - return bytes; -} diff --git a/src/DIPOLE/atom_vec_dipole.h b/src/DIPOLE/atom_vec_dipole.h index c6ee23def1..6abcb4e2ea 100644 --- a/src/DIPOLE/atom_vec_dipole.h +++ b/src/DIPOLE/atom_vec_dipole.h @@ -27,43 +27,7 @@ namespace LAMMPS_NS { class AtomVecDipole : public AtomVec { public: AtomVecDipole(class LAMMPS *); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *q,**mu; }; } @@ -73,13 +37,4 @@ class AtomVecDipole : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/MOLECULE/atom_vec_angle.cpp b/src/MOLECULE/atom_vec_angle.cpp index 4eba471b8f..79f5a7853e 100644 --- a/src/MOLECULE/atom_vec_angle.cpp +++ b/src/MOLECULE/atom_vec_angle.cpp @@ -13,13 +13,6 @@ #include "atom_vec_angle.h" #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" -#include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -31,895 +24,140 @@ AtomVecAngle::AtomVecAngle(LAMMPS *lmp) : AtomVec(lmp) bonds_allow = angles_allow = 1; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 7; - size_velocity = 3; - size_data_atom = 6; - size_data_vel = 4; - xcol_data = 4; - atom->molecule_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecAngle::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - - nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial"); - special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special"); - - num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond"); - bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom, - "atom:bond_type"); - bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom, - "atom:bond_atom"); - - num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle"); - angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom, - "atom:angle_type"); - angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom, - "atom:angle_atom1"); - angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom, - "atom:angle_atom2"); - angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom, - "atom:angle_atom3"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecAngle::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - molecule = atom->molecule; - nspecial = atom->nspecial; special = atom->special; - num_bond = atom->num_bond; bond_type = atom->bond_type; - bond_atom = atom->bond_atom; - num_angle = atom->num_angle; angle_type = atom->angle_type; - angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; - angle_atom3 = atom->angle_atom3; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecAngle::copy(int i, int j, int delflag) -{ - int k; - - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - molecule[j] = molecule[i]; - - num_bond[j] = num_bond[i]; - for (k = 0; k < num_bond[j]; k++) { - bond_type[j][k] = bond_type[i][k]; - bond_atom[j][k] = bond_atom[i][k]; - } - - num_angle[j] = num_angle[i]; - for (k = 0; k < num_angle[j]; k++) { - angle_type[j][k] = angle_type[i][k]; - angle_atom1[j][k] = angle_atom1[i][k]; - angle_atom2[j][k] = angle_atom2[i][k]; - angle_atom3[j][k] = angle_atom3[i][k]; - } - - nspecial[j][0] = nspecial[i][0]; - nspecial[j][1] = nspecial[i][1]; - nspecial[j][2] = nspecial[i][2]; - for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAngle::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - 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++]; - } + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 nspecial special"; + fields_copy = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 nspecial special"; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = (char *) "molecule"; + fields_border_vel = (char *) "molecule"; + fields_exchange = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 nspecial special"; + fields_restart = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3"; + fields_create = (char *) "molecule num_bond num_angle nspecial"; + fields_data_atom = (char *) "id molecule type x"; + fields_data_vel = NULL; + + setup_fields(); + + bond_per_atom = angle_per_atom = 0; + bond_negative = angle_negative = NULL; } /* ---------------------------------------------------------------------- */ -void AtomVecAngle::unpack_comm_vel(int n, int first, double *buf) +AtomVecAngle::~AtomVecAngle() { - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAngle::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = ubuf(molecule[j]).d; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAngle::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAngle::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - molecule[i] = (tagint) ubuf(buf[m++]).i; - return m; + delete [] bond_negative; + delete [] angle_negative; } /* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them + pack atom I's data for restart file + modify/unmodify values for default AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecAngle::pack_exchange(int i, double *buf) +int AtomVecAngle::pack_restart(int i, double *buf) { - int k; - - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; + // insure negative vectors are needed length - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(bond_type[i][k]).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (bond_per_atom < atom->bond_per_atom) { + delete [] bond_negative; + bond_per_atom = atom->bond_per_atom; + bond_negative = new int[bond_per_atom]; } - - buf[m++] = ubuf(num_angle[i]).d; - for (k = 0; k < num_angle[i]; k++) { - buf[m++] = ubuf(angle_type[i][k]).d; - buf[m++] = ubuf(angle_atom1[i][k]).d; - buf[m++] = ubuf(angle_atom2[i][k]).d; - buf[m++] = ubuf(angle_atom3[i][k]).d; + if (angle_per_atom < atom->angle_per_atom) { + delete [] angle_negative; + angle_per_atom = atom->angle_per_atom; + angle_negative = new int[angle_per_atom]; } - buf[m++] = ubuf(nspecial[i][0]).d; - buf[m++] = ubuf(nspecial[i][1]).d; - buf[m++] = ubuf(nspecial[i][2]).d; - for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAngle::unpack_exchange(double *buf) -{ - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; + // flip any negative types to positive and flag which ones - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; + int *num_angle = atom->num_angle; + int **angle_type = atom->angle_type; - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_bond_negative = 0; + for (int m = 0; m < num_bond[i]; m++) { + if (bond_type[i][m] < 0) { + bond_negative[m] = 1; + bond_type[i][m] = -bond_type[i][m]; + any_bond_negative = 1; + } else bond_negative[m] = 0; } - num_angle[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_angle[nlocal]; k++) { - angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; - angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_angle_negative = 0; + for (int m = 0; m < num_angle[i]; m++) { + if (angle_type[i][m] < 0) { + angle_negative[m] = 1; + angle_type[i][m] = -angle_type[i][m]; + any_angle_negative = 1; + } else angle_negative[m] = 0; } - nspecial[nlocal][0] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][1] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][2] = (int) ubuf(buf[m++]).i; - for (k = 0; k < nspecial[nlocal][2]; k++) - special[nlocal][k] = (tagint) ubuf(buf[m++]).i; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ + // perform the pack with adjusted values -int AtomVecAngle::size_restart() -{ - int i; + int n = AtomVec::pack_restart(i,buf); - int nlocal = atom->nlocal; - int n = 0; - for (i = 0; i < nlocal; i++) - n += 14 + 2*num_bond[i] + 4*num_angle[i]; + // restore the flagged types to their negative values - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecAngle::pack_restart(int i, double *buf) -{ - int k; - - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (any_bond_negative) { + for (int m = 0; m < num_bond[i]; m++) + if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } - - buf[m++] = ubuf(num_angle[i]).d; - for (k = 0; k < num_angle[i]; k++) { - buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d; - buf[m++] = ubuf(angle_atom1[i][k]).d; - buf[m++] = ubuf(angle_atom2[i][k]).d; - buf[m++] = ubuf(angle_atom3[i][k]).d; + if (any_angle_negative) { + for (int m = 0; m < num_angle[i]; m++) + if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; + return n; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities + initialize other atom quantities ------------------------------------------------------------------------- */ int AtomVecAngle::unpack_restart(double *buf) { - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_angle[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_angle[nlocal]; k++) { - angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; - angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecAngle::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); + AtomVec::unpack_restart(buf); + int ilocal = atom->nlocal-1; - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - molecule[nlocal] = 0; - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - atom->nlocal++; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecAngle::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecAngle::data_atom_hybrid(int nlocal, char **values) -{ - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecAngle::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(type[i]).d; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecAngle::pack_data_hybrid(int i, double *buf) -{ - buf[0] = ubuf(molecule[i]).d; - return 1; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecAngle::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i, - buf[i][3],buf[i][4],buf[i][5], - (int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i, - (int) ubuf(buf[i][8]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecAngle::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT,(tagint) ubuf(buf[0]).i); - return 1; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecAngle::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3); - if (atom->memcheck("special")) - bytes += memory->usage(special,nmax,atom->maxspecial); - - if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax); - if (atom->memcheck("bond_type")) - bytes += memory->usage(bond_type,nmax,atom->bond_per_atom); - if (atom->memcheck("bond_atom")) - bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom); - - if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax); - if (atom->memcheck("angle_type")) - bytes += memory->usage(angle_type,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom1")) - bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom2")) - bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom3")) - bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom); + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; - return bytes; + atom->num_bond[ilocal] = 0; + atom->num_angle[ilocal] = 0; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_angle.h b/src/MOLECULE/atom_vec_angle.h index 9030cce0d8..6511b517ee 100644 --- a/src/MOLECULE/atom_vec_angle.h +++ b/src/MOLECULE/atom_vec_angle.h @@ -27,50 +27,14 @@ namespace LAMMPS_NS { class AtomVecAngle : public AtomVec { public: AtomVecAngle(class LAMMPS *); - virtual ~AtomVecAngle() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); + ~AtomVecAngle(); int pack_restart(int, double *); int unpack_restart(double *); - void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - tagint *molecule; - int **nspecial; - tagint **special; - int *num_bond; - int **bond_type; - tagint **bond_atom; - int *num_angle; - int **angle_type; - tagint **angle_atom1,**angle_atom2,**angle_atom3; + private: + int bond_per_atom,angle_per_atom; + int *bond_negative,*angle_negative; }; } @@ -80,13 +44,4 @@ class AtomVecAngle : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp index 0bcd614f94..20cdfdd65a 100644 --- a/src/MOLECULE/atom_vec_bond.cpp +++ b/src/MOLECULE/atom_vec_bond.cpp @@ -13,13 +13,6 @@ #include "atom_vec_bond.h" #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" -#include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -31,829 +24,113 @@ AtomVecBond::AtomVecBond(LAMMPS *lmp) : AtomVec(lmp) bonds_allow = 1; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 7; - size_velocity = 3; - size_data_atom = 6; - size_data_vel = 4; - xcol_data = 4; - atom->molecule_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecBond::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - - nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial"); - special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special"); - - num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond"); - bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom, - "atom:bond_type"); - bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom, - "atom:bond_atom"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecBond::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - molecule = atom->molecule; - nspecial = atom->nspecial; special = atom->special; - num_bond = atom->num_bond; bond_type = atom->bond_type; - bond_atom = atom->bond_atom; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecBond::copy(int i, int j, int delflag) -{ - int k; - - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - molecule[j] = molecule[i]; - - num_bond[j] = num_bond[i]; - for (k = 0; k < num_bond[j]; k++) { - bond_type[j][k] = bond_type[i][k]; - bond_atom[j][k] = bond_atom[i][k]; - } - - nspecial[j][0] = nspecial[i][0]; - nspecial[j][1] = nspecial[i][1]; - nspecial[j][2] = nspecial[i][2]; - for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) + "molecule num_bond bond_type bond_atom nspecial special"; + fields_copy = (char *) + "molecule num_bond bond_type bond_atom nspecial special"; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = (char *) "molecule"; + fields_border_vel = (char *) "molecule"; + fields_exchange = (char *) + "molecule num_bond bond_type bond_atom nspecial special"; + fields_restart = (char *) "molecule num_bond bond_type bond_atom"; + fields_create = (char *) "molecule num_bond nspecial"; + fields_data_atom = (char *) "id molecule type x"; + fields_data_vel = NULL; + + setup_fields(); + + bond_per_atom = 0; + bond_negative = NULL; } /* ---------------------------------------------------------------------- */ -int AtomVecBond::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) +AtomVecBond::~AtomVecBond() { - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBond::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBond::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBond::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = ubuf(molecule[j]).d; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBond::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBond::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - molecule[i] = (tagint) ubuf(buf[m++]).i; - return m; + delete [] bond_negative; } /* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them + pack atom I's data for restart file + modify/unmodify values for default AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecBond::pack_exchange(int i, double *buf) +int AtomVecBond::pack_restart(int i, double *buf) { - int k; + // insure bond_negative vector is needed length - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(bond_type[i][k]).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (bond_per_atom < atom->bond_per_atom) { + delete [] bond_negative; + bond_per_atom = atom->bond_per_atom; + bond_negative = new int[bond_per_atom]; } - buf[m++] = ubuf(nspecial[i][0]).d; - buf[m++] = ubuf(nspecial[i][1]).d; - buf[m++] = ubuf(nspecial[i][2]).d; - for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d; + // flip any negative types to positive and flag which ones - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; -/* ---------------------------------------------------------------------- */ - -int AtomVecBond::unpack_exchange(double *buf) -{ - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_bond_negative = 0; + for (int m = 0; m < num_bond[i]; m++) { + if (bond_type[i][m] < 0) { + bond_negative[m] = 1; + bond_type[i][m] = -bond_type[i][m]; + any_bond_negative = 1; + } else bond_negative[m] = 0; } - nspecial[nlocal][0] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][1] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][2] = (int) ubuf(buf[m++]).i; - for (k = 0; k < nspecial[nlocal][2]; k++) - special[nlocal][k] = (tagint) ubuf(buf[m++]).i; + // perform the pack with adjusted values - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); + int n = AtomVec::pack_restart(i,buf); - atom->nlocal++; - return m; -} + // restore the flagged types to their negative values -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecBond::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 0; - for (i = 0; i < nlocal; i++) - n += 13 + 2*num_bond[i]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecBond::pack_restart(int i, double *buf) -{ - int k; - - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (any_bond_negative) { + for (int m = 0; m < num_bond[i]; m++) + if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; + return n; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities + initialize other atom quantities ------------------------------------------------------------------------- */ int AtomVecBond::unpack_restart(double *buf) { - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecBond::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; + AtomVec::unpack_restart(buf); + int ilocal = atom->nlocal-1; - molecule[nlocal] = 0; - num_bond[nlocal] = 0; - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - atom->nlocal++; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecBond::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - num_bond[nlocal] = 0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecBond::data_atom_hybrid(int nlocal, char **values) -{ - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - - num_bond[nlocal] = 0; - - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecBond::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(type[i]).d; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecBond::pack_data_hybrid(int i, double *buf) -{ - buf[0] = ubuf(molecule[i]).d; - return 1; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecBond::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i, - buf[i][3],buf[i][4],buf[i][5], - (int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i, - (int) ubuf(buf[i][8]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecBond::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT,(tagint) ubuf(buf[0]).i); - return 1; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecBond::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3); - if (atom->memcheck("special")) - bytes += memory->usage(special,nmax,atom->maxspecial); - - if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax); - if (atom->memcheck("bond_type")) - bytes += memory->usage(bond_type,nmax,atom->bond_per_atom); - if (atom->memcheck("bond_atom")) - bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom); + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; - return bytes; + atom->num_bond[ilocal] = 0; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_bond.h b/src/MOLECULE/atom_vec_bond.h index d7370d4659..9245bc317a 100644 --- a/src/MOLECULE/atom_vec_bond.h +++ b/src/MOLECULE/atom_vec_bond.h @@ -27,46 +27,14 @@ namespace LAMMPS_NS { class AtomVecBond : public AtomVec { public: AtomVecBond(class LAMMPS *); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); + ~AtomVecBond(); int pack_restart(int, double *); int unpack_restart(double *); - void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - tagint *molecule; - int **nspecial; - tagint **special; - int *num_bond; - int **bond_type; - tagint **bond_atom; + int bond_per_atom; + int *bond_negative; }; } @@ -76,13 +44,4 @@ class AtomVecBond : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp index 76c60ba121..826d5fea4e 100644 --- a/src/MOLECULE/atom_vec_full.cpp +++ b/src/MOLECULE/atom_vec_full.cpp @@ -13,13 +13,6 @@ #include "atom_vec_full.h" #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" -#include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -31,1078 +24,204 @@ AtomVecFull::AtomVecFull(LAMMPS *lmp) : AtomVec(lmp) bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 8; - size_velocity = 3; - size_data_atom = 7; - size_data_vel = 4; - xcol_data = 5; - atom->molecule_flag = atom->q_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecFull::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - q = memory->grow(atom->q,nmax,"atom:q"); - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - - nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial"); - special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special"); - - num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond"); - bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom, - "atom:bond_type"); - bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom, - "atom:bond_atom"); - - num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle"); - angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom, - "atom:angle_type"); - angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom, - "atom:angle_atom1"); - angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom, - "atom:angle_atom2"); - angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom, - "atom:angle_atom3"); - - num_dihedral = memory->grow(atom->num_dihedral,nmax,"atom:num_dihedral"); - dihedral_type = memory->grow(atom->dihedral_type,nmax, - atom->dihedral_per_atom,"atom:dihedral_type"); - dihedral_atom1 = - memory->grow(atom->dihedral_atom1,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom1"); - dihedral_atom2 = - memory->grow(atom->dihedral_atom2,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom2"); - dihedral_atom3 = - memory->grow(atom->dihedral_atom3,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom3"); - dihedral_atom4 = - memory->grow(atom->dihedral_atom4,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom4"); - - num_improper = memory->grow(atom->num_improper,nmax,"atom:num_improper"); - improper_type = - memory->grow(atom->improper_type,nmax,atom->improper_per_atom, - "atom:improper_type"); - improper_atom1 = - memory->grow(atom->improper_atom1,nmax,atom->improper_per_atom, - "atom:improper_atom1"); - improper_atom2 = - memory->grow(atom->improper_atom2,nmax,atom->improper_per_atom, - "atom:improper_atom2"); - improper_atom3 = - memory->grow(atom->improper_atom3,nmax,atom->improper_per_atom, - "atom:improper_atom3"); - improper_atom4 = - memory->grow(atom->improper_atom4,nmax,atom->improper_per_atom, - "atom:improper_atom4"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecFull::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - q = atom->q; molecule = atom->molecule; - nspecial = atom->nspecial; special = atom->special; - num_bond = atom->num_bond; bond_type = atom->bond_type; - bond_atom = atom->bond_atom; - num_angle = atom->num_angle; angle_type = atom->angle_type; - angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; - angle_atom3 = atom->angle_atom3; - num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type; - dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2; - dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4; - num_improper = atom->num_improper; improper_type = atom->improper_type; - improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2; - improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecFull::copy(int i, int j, int delflag) -{ - int k; - - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - q[j] = q[i]; - molecule[j] = molecule[i]; - - num_bond[j] = num_bond[i]; - for (k = 0; k < num_bond[j]; k++) { - bond_type[j][k] = bond_type[i][k]; - bond_atom[j][k] = bond_atom[i][k]; - } - - num_angle[j] = num_angle[i]; - for (k = 0; k < num_angle[j]; k++) { - angle_type[j][k] = angle_type[i][k]; - angle_atom1[j][k] = angle_atom1[i][k]; - angle_atom2[j][k] = angle_atom2[i][k]; - angle_atom3[j][k] = angle_atom3[i][k]; - } - - num_dihedral[j] = num_dihedral[i]; - for (k = 0; k < num_dihedral[j]; k++) { - dihedral_type[j][k] = dihedral_type[i][k]; - dihedral_atom1[j][k] = dihedral_atom1[i][k]; - dihedral_atom2[j][k] = dihedral_atom2[i][k]; - dihedral_atom3[j][k] = dihedral_atom3[i][k]; - dihedral_atom4[j][k] = dihedral_atom4[i][k]; - } - - num_improper[j] = num_improper[i]; - for (k = 0; k < num_improper[j]; k++) { - improper_type[j][k] = improper_type[i][k]; - improper_atom1[j][k] = improper_atom1[i][k]; - improper_atom2[j][k] = improper_atom2[i][k]; - improper_atom3[j][k] = improper_atom3[i][k]; - improper_atom4[j][k] = improper_atom4[i][k]; - } - - nspecial[j][0] = nspecial[i][0]; - nspecial[j][1] = nspecial[i][1]; - nspecial[j][2] = nspecial[i][2]; - for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecFull::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecFull::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecFull::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(molecule[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(molecule[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(molecule[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = q[j]; - buf[m++] = ubuf(molecule[j]).d; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecFull::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - molecule[i] = (tagint) ubuf(buf[m++]).i; - } - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) + "q molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4 " + "nspecial special"; + fields_copy = (char *) + "q molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4 " + "nspecial special"; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = (char *) "q molecule"; + fields_border_vel = (char *) "q molecule"; + fields_exchange = (char *) + "q molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4 " + "nspecial special"; + fields_restart = (char *) + "q molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4"; + fields_create = (char *) + "q molecule num_bond num_angle num_dihedral num_improper nspecial"; + fields_data_atom = (char *) "id molecule type q x"; + fields_data_vel = NULL; + + setup_fields(); + + bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0; + bond_negative = angle_negative = dihedral_negative = improper_negative = NULL; } /* ---------------------------------------------------------------------- */ -void AtomVecFull::unpack_border_vel(int n, int first, double *buf) +AtomVecFull::~AtomVecFull() { - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - molecule[i] = (tagint) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - q[i] = buf[m++]; - molecule[i] = (tagint) ubuf(buf[m++]).i; - } - return m; + delete [] bond_negative; + delete [] angle_negative; + delete [] dihedral_negative; + delete [] improper_negative; } /* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them + pack atom I's data for restart file + modify/unmodify values for default AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecFull::pack_exchange(int i, double *buf) +int AtomVecFull::pack_restart(int i, double *buf) { - int k; + // insure negative vectors are needed length - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = q[i]; - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(bond_type[i][k]).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (bond_per_atom < atom->bond_per_atom) { + delete [] bond_negative; + bond_per_atom = atom->bond_per_atom; + bond_negative = new int[bond_per_atom]; } - - buf[m++] = ubuf(num_angle[i]).d; - for (k = 0; k < num_angle[i]; k++) { - buf[m++] = ubuf(angle_type[i][k]).d; - buf[m++] = ubuf(angle_atom1[i][k]).d; - buf[m++] = ubuf(angle_atom2[i][k]).d; - buf[m++] = ubuf(angle_atom3[i][k]).d; + if (angle_per_atom < atom->angle_per_atom) { + delete [] angle_negative; + angle_per_atom = atom->angle_per_atom; + angle_negative = new int[angle_per_atom]; } - - buf[m++] = ubuf(num_dihedral[i]).d; - for (k = 0; k < num_dihedral[i]; k++) { - buf[m++] = ubuf(dihedral_type[i][k]).d; - buf[m++] = ubuf(dihedral_atom1[i][k]).d; - buf[m++] = ubuf(dihedral_atom2[i][k]).d; - buf[m++] = ubuf(dihedral_atom3[i][k]).d; - buf[m++] = ubuf(dihedral_atom4[i][k]).d; + if (dihedral_per_atom < atom->dihedral_per_atom) { + delete [] dihedral_negative; + dihedral_per_atom = atom->dihedral_per_atom; + dihedral_negative = new int[dihedral_per_atom]; } - - buf[m++] = ubuf(num_improper[i]).d; - for (k = 0; k < num_improper[i]; k++) { - buf[m++] = ubuf(improper_type[i][k]).d; - buf[m++] = ubuf(improper_atom1[i][k]).d; - buf[m++] = ubuf(improper_atom2[i][k]).d; - buf[m++] = ubuf(improper_atom3[i][k]).d; - buf[m++] = ubuf(improper_atom4[i][k]).d; + if (improper_per_atom < atom->improper_per_atom) { + delete [] improper_negative; + improper_per_atom = atom->improper_per_atom; + improper_negative = new int[improper_per_atom]; } - buf[m++] = ubuf(nspecial[i][0]).d; - buf[m++] = ubuf(nspecial[i][1]).d; - buf[m++] = ubuf(nspecial[i][2]).d; - for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecFull::unpack_exchange(double *buf) -{ - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); + // flip any negative types to positive and flag which ones - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; + int *num_angle = atom->num_angle; + int **angle_type = atom->angle_type; + int *num_dihedral = atom->num_dihedral; + int **dihedral_type = atom->dihedral_type; + int *num_improper = atom->num_improper; + int **improper_type = atom->improper_type; - q[nlocal] = buf[m++]; - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_bond_negative = 0; + for (int m = 0; m < num_bond[i]; m++) { + if (bond_type[i][m] < 0) { + bond_negative[m] = 1; + bond_type[i][m] = -bond_type[i][m]; + any_bond_negative = 1; + } else bond_negative[m] = 0; } - num_angle[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_angle[nlocal]; k++) { - angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; - angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_angle_negative = 0; + for (int m = 0; m < num_angle[i]; m++) { + if (angle_type[i][m] < 0) { + angle_negative[m] = 1; + angle_type[i][m] = -angle_type[i][m]; + any_angle_negative = 1; + } else angle_negative[m] = 0; } - num_dihedral[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_dihedral[nlocal]; k++) { - dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i; - dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_dihedral_negative = 0; + for (int m = 0; m < num_dihedral[i]; m++) { + if (dihedral_type[i][m] < 0) { + dihedral_negative[m] = 1; + dihedral_type[i][m] = -dihedral_type[i][m]; + any_dihedral_negative = 1; + } else dihedral_negative[m] = 0; } - num_improper[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_improper[nlocal]; k++) { - improper_type[nlocal][k] = (int) ubuf(buf[m++]).i; - improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_improper_negative = 0; + for (int m = 0; m < num_improper[i]; m++) { + if (improper_type[i][m] < 0) { + improper_negative[m] = 1; + improper_type[i][m] = -improper_type[i][m]; + any_improper_negative = 1; + } else improper_negative[m] = 0; } - nspecial[nlocal][0] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][1] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][2] = (int) ubuf(buf[m++]).i; - for (k = 0; k < nspecial[nlocal][2]; k++) - special[nlocal][k] = (tagint) ubuf(buf[m++]).i; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecFull::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 0; - for (i = 0; i < nlocal; i++) - n += 17 + 2*num_bond[i] + 4*num_angle[i] + - 5*num_dihedral[i] + 5*num_improper[i]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecFull::pack_restart(int i, double *buf) -{ - int k; + // perform the pack with adjusted values - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; + int n = AtomVec::pack_restart(i,buf); - buf[m++] = q[i]; - buf[m++] = ubuf(molecule[i]).d; + // restore the flagged types to their negative values - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (any_bond_negative) { + for (int m = 0; m < num_bond[i]; m++) + if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } - - buf[m++] = ubuf(num_angle[i]).d; - for (k = 0; k < num_angle[i]; k++) { - buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d; - buf[m++] = ubuf(angle_atom1[i][k]).d; - buf[m++] = ubuf(angle_atom2[i][k]).d; - buf[m++] = ubuf(angle_atom3[i][k]).d; + if (any_angle_negative) { + for (int m = 0; m < num_angle[i]; m++) + if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; } - - buf[m++] = ubuf(num_dihedral[i]).d; - for (k = 0; k < num_dihedral[i]; k++) { - buf[m++] = ubuf(MAX(dihedral_type[i][k],-dihedral_type[i][k])).d; - buf[m++] = ubuf(dihedral_atom1[i][k]).d; - buf[m++] = ubuf(dihedral_atom2[i][k]).d; - buf[m++] = ubuf(dihedral_atom3[i][k]).d; - buf[m++] = ubuf(dihedral_atom4[i][k]).d; + if (any_dihedral_negative) { + for (int m = 0; m < num_dihedral[i]; m++) + if (dihedral_negative[m]) dihedral_type[i][m] = -dihedral_type[i][m]; } - - buf[m++] = ubuf(num_improper[i]).d; - for (k = 0; k < num_improper[i]; k++) { - buf[m++] = ubuf(MAX(improper_type[i][k],-improper_type[i][k])).d; - buf[m++] = ubuf(improper_atom1[i][k]).d; - buf[m++] = ubuf(improper_atom2[i][k]).d; - buf[m++] = ubuf(improper_atom3[i][k]).d; - buf[m++] = ubuf(improper_atom4[i][k]).d; + if (any_improper_negative) { + for (int m = 0; m < num_improper[i]; m++) + if (improper_negative[m]) improper_type[i][m] = -improper_type[i][m]; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; + return n; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities + initialize other atom quantities ------------------------------------------------------------------------- */ int AtomVecFull::unpack_restart(double *buf) { - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } + AtomVec::unpack_restart(buf); + int ilocal = atom->nlocal-1; - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - q[nlocal] = buf[m++]; - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_angle[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_angle[nlocal]; k++) { - angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; - angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_dihedral[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_dihedral[nlocal]; k++) { - dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i; - dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_improper[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_improper[nlocal]; k++) { - improper_type[nlocal][k] = (int) ubuf(buf[m++]).i; - improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecFull::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - q[nlocal] = 0.0; - molecule[nlocal] = 0; - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - num_dihedral[nlocal] = 0; - num_improper[nlocal] = 0; - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - atom->nlocal++; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecFull::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - q[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - num_dihedral[nlocal] = 0; - num_improper[nlocal] = 0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecFull::data_atom_hybrid(int nlocal, char **values) -{ - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - q[nlocal] = utils::numeric(FLERR,values[1],true,lmp); - - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - num_dihedral[nlocal] = 0; - num_improper[nlocal] = 0; - - return 2; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecFull::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(type[i]).d; - buf[i][3] = q[i]; - buf[i][4] = x[i][0]; - buf[i][5] = x[i][1]; - buf[i][6] = x[i][2]; - buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecFull::pack_data_hybrid(int i, double *buf) -{ - buf[0] = ubuf(molecule[i]).d; - buf[1] = q[i]; - return 2; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecFull::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i, - buf[i][3],buf[i][4],buf[i][5],buf[i][6], - (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i, - (int) ubuf(buf[i][9]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecFull::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT " %-1.16e",(tagint) ubuf(buf[0]).i,buf[1]); - return 2; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecFull::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("q")) bytes += memory->usage(q,nmax); - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3); - if (atom->memcheck("special")) - bytes += memory->usage(special,nmax,atom->maxspecial); - - if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax); - if (atom->memcheck("bond_type")) - bytes += memory->usage(bond_type,nmax,atom->bond_per_atom); - if (atom->memcheck("bond_atom")) - bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom); - - if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax); - if (atom->memcheck("angle_type")) - bytes += memory->usage(angle_type,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom1")) - bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom2")) - bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom3")) - bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom); - - if (atom->memcheck("num_dihedral")) bytes += memory->usage(num_dihedral,nmax); - if (atom->memcheck("dihedral_type")) - bytes += memory->usage(dihedral_type,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom1")) - bytes += memory->usage(dihedral_atom1,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom2")) - bytes += memory->usage(dihedral_atom2,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom3")) - bytes += memory->usage(dihedral_atom3,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom4")) - bytes += memory->usage(dihedral_atom4,nmax,atom->dihedral_per_atom); - - if (atom->memcheck("num_improper")) bytes += memory->usage(num_improper,nmax); - if (atom->memcheck("improper_type")) - bytes += memory->usage(improper_type,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom1")) - bytes += memory->usage(improper_atom1,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom2")) - bytes += memory->usage(improper_atom2,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom3")) - bytes += memory->usage(improper_atom3,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom4")) - bytes += memory->usage(improper_atom4,nmax,atom->improper_per_atom); + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; - return bytes; + atom->num_bond[ilocal] = 0; + atom->num_angle[ilocal] = 0; + atom->num_dihedral[ilocal] = 0; + atom->num_improper[ilocal] = 0; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_full.h b/src/MOLECULE/atom_vec_full.h index abaf570b17..b194a86994 100644 --- a/src/MOLECULE/atom_vec_full.h +++ b/src/MOLECULE/atom_vec_full.h @@ -27,57 +27,14 @@ namespace LAMMPS_NS { class AtomVecFull : public AtomVec { public: AtomVecFull(class LAMMPS *); - virtual ~AtomVecFull() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); + ~AtomVecFull(); int pack_restart(int, double *); int unpack_restart(double *); - void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *q; - tagint *molecule; - int **nspecial; - tagint **special; - int *num_bond; - int **bond_type; - tagint **bond_atom; - int *num_angle; - int **angle_type; - tagint **angle_atom1,**angle_atom2,**angle_atom3; - int *num_dihedral; - int **dihedral_type; - tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; - int *num_improper; - int **improper_type; - tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; + private: + int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; + int *bond_negative,*angle_negative,*dihedral_negative,*improper_negative; }; } @@ -87,13 +44,4 @@ class AtomVecFull : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp index 73cec70456..dad7c5cea6 100644 --- a/src/MOLECULE/atom_vec_molecular.cpp +++ b/src/MOLECULE/atom_vec_molecular.cpp @@ -13,13 +13,6 @@ #include "atom_vec_molecular.h" #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" -#include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -31,1056 +24,204 @@ AtomVecMolecular::AtomVecMolecular(LAMMPS *lmp) : AtomVec(lmp) bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 1; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 7; - size_velocity = 3; - size_data_atom = 6; - size_data_vel = 4; - xcol_data = 4; - atom->molecule_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecMolecular::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - - nspecial = memory->grow(atom->nspecial,nmax,3,"atom:nspecial"); - special = memory->grow(atom->special,nmax,atom->maxspecial,"atom:special"); - - num_bond = memory->grow(atom->num_bond,nmax,"atom:num_bond"); - bond_type = memory->grow(atom->bond_type,nmax,atom->bond_per_atom, - "atom:bond_type"); - bond_atom = memory->grow(atom->bond_atom,nmax,atom->bond_per_atom, - "atom:bond_atom"); - - num_angle = memory->grow(atom->num_angle,nmax,"atom:num_angle"); - angle_type = memory->grow(atom->angle_type,nmax,atom->angle_per_atom, - "atom:angle_type"); - angle_atom1 = memory->grow(atom->angle_atom1,nmax,atom->angle_per_atom, - "atom:angle_atom1"); - angle_atom2 = memory->grow(atom->angle_atom2,nmax,atom->angle_per_atom, - "atom:angle_atom2"); - angle_atom3 = memory->grow(atom->angle_atom3,nmax,atom->angle_per_atom, - "atom:angle_atom3"); - - num_dihedral = memory->grow(atom->num_dihedral,nmax,"atom:num_dihedral"); - dihedral_type = memory->grow(atom->dihedral_type,nmax, - atom->dihedral_per_atom,"atom:dihedral_type"); - dihedral_atom1 = - memory->grow(atom->dihedral_atom1,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom1"); - dihedral_atom2 = - memory->grow(atom->dihedral_atom2,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom2"); - dihedral_atom3 = - memory->grow(atom->dihedral_atom3,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom3"); - dihedral_atom4 = - memory->grow(atom->dihedral_atom4,nmax,atom->dihedral_per_atom, - "atom:dihedral_atom4"); - - num_improper = memory->grow(atom->num_improper,nmax,"atom:num_improper"); - improper_type = - memory->grow(atom->improper_type,nmax,atom->improper_per_atom, - "atom:improper_type"); - improper_atom1 = - memory->grow(atom->improper_atom1,nmax,atom->improper_per_atom, - "atom:improper_atom1"); - improper_atom2 = - memory->grow(atom->improper_atom2,nmax,atom->improper_per_atom, - "atom:improper_atom2"); - improper_atom3 = - memory->grow(atom->improper_atom3,nmax,atom->improper_per_atom, - "atom:improper_atom3"); - improper_atom4 = - memory->grow(atom->improper_atom4,nmax,atom->improper_per_atom, - "atom:improper_atom4"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecMolecular::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - molecule = atom->molecule; - nspecial = atom->nspecial; special = atom->special; - num_bond = atom->num_bond; bond_type = atom->bond_type; - bond_atom = atom->bond_atom; - num_angle = atom->num_angle; angle_type = atom->angle_type; - angle_atom1 = atom->angle_atom1; angle_atom2 = atom->angle_atom2; - angle_atom3 = atom->angle_atom3; - num_dihedral = atom->num_dihedral; dihedral_type = atom->dihedral_type; - dihedral_atom1 = atom->dihedral_atom1; dihedral_atom2 = atom->dihedral_atom2; - dihedral_atom3 = atom->dihedral_atom3; dihedral_atom4 = atom->dihedral_atom4; - num_improper = atom->num_improper; improper_type = atom->improper_type; - improper_atom1 = atom->improper_atom1; improper_atom2 = atom->improper_atom2; - improper_atom3 = atom->improper_atom3; improper_atom4 = atom->improper_atom4; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecMolecular::copy(int i, int j, int delflag) -{ - int k; - - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - molecule[j] = molecule[i]; - - num_bond[j] = num_bond[i]; - for (k = 0; k < num_bond[j]; k++) { - bond_type[j][k] = bond_type[i][k]; - bond_atom[j][k] = bond_atom[i][k]; - } - - num_angle[j] = num_angle[i]; - for (k = 0; k < num_angle[j]; k++) { - angle_type[j][k] = angle_type[i][k]; - angle_atom1[j][k] = angle_atom1[i][k]; - angle_atom2[j][k] = angle_atom2[i][k]; - angle_atom3[j][k] = angle_atom3[i][k]; - } - - num_dihedral[j] = num_dihedral[i]; - for (k = 0; k < num_dihedral[j]; k++) { - dihedral_type[j][k] = dihedral_type[i][k]; - dihedral_atom1[j][k] = dihedral_atom1[i][k]; - dihedral_atom2[j][k] = dihedral_atom2[i][k]; - dihedral_atom3[j][k] = dihedral_atom3[i][k]; - dihedral_atom4[j][k] = dihedral_atom4[i][k]; - } - - num_improper[j] = num_improper[i]; - for (k = 0; k < num_improper[j]; k++) { - improper_type[j][k] = improper_type[i][k]; - improper_atom1[j][k] = improper_atom1[i][k]; - improper_atom2[j][k] = improper_atom2[i][k]; - improper_atom3[j][k] = improper_atom3[i][k]; - improper_atom4[j][k] = improper_atom4[i][k]; - } - - nspecial[j][0] = nspecial[i][0]; - nspecial[j][1] = nspecial[i][1]; - nspecial[j][2] = nspecial[i][2]; - for (k = 0; k < nspecial[j][2]; k++) special[j][k] = special[i][k]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ -int AtomVecMolecular::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4 " + "nspecial special"; + fields_copy = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4 " + "nspecial special"; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = (char *) "molecule"; + fields_border_vel = (char *) "molecule"; + fields_exchange = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4 " + "nspecial special"; + fields_restart = (char *) + "molecule num_bond bond_type bond_atom " + "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 " + "num_dihedral dihedral_type dihedral_atom1 dihedral_atom2 " + "dihedral_atom3 dihedral_atom4 " + "num_improper improper_type improper_atom1 improper_atom2 " + "improper_atom3 improper_atom4"; + fields_create = (char *) + "molecule num_bond num_angle num_dihedral num_improper nspecial"; + fields_data_atom = (char *) "id molecule type x"; + fields_data_vel = NULL; + + setup_fields(); + + bond_per_atom = angle_per_atom = dihedral_per_atom = improper_per_atom = 0; + bond_negative = angle_negative = dihedral_negative = improper_negative = NULL; } /* ---------------------------------------------------------------------- */ -void AtomVecMolecular::unpack_comm(int n, int first, double *buf) +AtomVecMolecular::~AtomVecMolecular() { - int i,m,last; - - 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++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMolecular::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMolecular::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = ubuf(molecule[j]).d; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMolecular::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMolecular::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - molecule[i] = (tagint) ubuf(buf[m++]).i; - return m; + delete [] bond_negative; + delete [] angle_negative; + delete [] dihedral_negative; + delete [] improper_negative; } /* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them + pack atom I's data for restart file + modify/unmodify values for default AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecMolecular::pack_exchange(int i, double *buf) +int AtomVecMolecular::pack_restart(int i, double *buf) { - int k; + // insure negative vectors are needed length - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(bond_type[i][k]).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (bond_per_atom < atom->bond_per_atom) { + delete [] bond_negative; + bond_per_atom = atom->bond_per_atom; + bond_negative = new int[bond_per_atom]; } - - buf[m++] = ubuf(num_angle[i]).d; - for (k = 0; k < num_angle[i]; k++) { - buf[m++] = ubuf(angle_type[i][k]).d; - buf[m++] = ubuf(angle_atom1[i][k]).d; - buf[m++] = ubuf(angle_atom2[i][k]).d; - buf[m++] = ubuf(angle_atom3[i][k]).d; + if (angle_per_atom < atom->angle_per_atom) { + delete [] angle_negative; + angle_per_atom = atom->angle_per_atom; + angle_negative = new int[angle_per_atom]; } - - buf[m++] = ubuf(num_dihedral[i]).d; - for (k = 0; k < num_dihedral[i]; k++) { - buf[m++] = ubuf(dihedral_type[i][k]).d; - buf[m++] = ubuf(dihedral_atom1[i][k]).d; - buf[m++] = ubuf(dihedral_atom2[i][k]).d; - buf[m++] = ubuf(dihedral_atom3[i][k]).d; - buf[m++] = ubuf(dihedral_atom4[i][k]).d; + if (dihedral_per_atom < atom->dihedral_per_atom) { + delete [] dihedral_negative; + dihedral_per_atom = atom->dihedral_per_atom; + dihedral_negative = new int[dihedral_per_atom]; } - - buf[m++] = ubuf(num_improper[i]).d; - for (k = 0; k < num_improper[i]; k++) { - buf[m++] = ubuf(improper_type[i][k]).d; - buf[m++] = ubuf(improper_atom1[i][k]).d; - buf[m++] = ubuf(improper_atom2[i][k]).d; - buf[m++] = ubuf(improper_atom3[i][k]).d; - buf[m++] = ubuf(improper_atom4[i][k]).d; + if (improper_per_atom < atom->improper_per_atom) { + delete [] improper_negative; + improper_per_atom = atom->improper_per_atom; + improper_negative = new int[improper_per_atom]; } - buf[m++] = ubuf(nspecial[i][0]).d; - buf[m++] = ubuf(nspecial[i][1]).d; - buf[m++] = ubuf(nspecial[i][2]).d; - for (k = 0; k < nspecial[i][2]; k++) buf[m++] = ubuf(special[i][k]).d; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMolecular::unpack_exchange(double *buf) -{ - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); + // flip any negative types to positive and flag which ones - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; + int *num_angle = atom->num_angle; + int **angle_type = atom->angle_type; + int *num_dihedral = atom->num_dihedral; + int **dihedral_type = atom->dihedral_type; + int *num_improper = atom->num_improper; + int **improper_type = atom->improper_type; - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_bond_negative = 0; + for (int m = 0; m < num_bond[i]; m++) { + if (bond_type[i][m] < 0) { + bond_negative[m] = 1; + bond_type[i][m] = -bond_type[i][m]; + any_bond_negative = 1; + } else bond_negative[m] = 0; } - num_angle[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_angle[nlocal]; k++) { - angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; - angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_angle_negative = 0; + for (int m = 0; m < num_angle[i]; m++) { + if (angle_type[i][m] < 0) { + angle_negative[m] = 1; + angle_type[i][m] = -angle_type[i][m]; + any_angle_negative = 1; + } else angle_negative[m] = 0; } - num_dihedral[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_dihedral[nlocal]; k++) { - dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i; - dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_dihedral_negative = 0; + for (int m = 0; m < num_dihedral[i]; m++) { + if (dihedral_type[i][m] < 0) { + dihedral_negative[m] = 1; + dihedral_type[i][m] = -dihedral_type[i][m]; + any_dihedral_negative = 1; + } else dihedral_negative[m] = 0; } - num_improper[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_improper[nlocal]; k++) { - improper_type[nlocal][k] = (int) ubuf(buf[m++]).i; - improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; + int any_improper_negative = 0; + for (int m = 0; m < num_improper[i]; m++) { + if (improper_type[i][m] < 0) { + improper_negative[m] = 1; + improper_type[i][m] = -improper_type[i][m]; + any_improper_negative = 1; + } else improper_negative[m] = 0; } - nspecial[nlocal][0] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][1] = (int) ubuf(buf[m++]).i; - nspecial[nlocal][2] = (int) ubuf(buf[m++]).i; - for (k = 0; k < nspecial[nlocal][2]; k++) - special[nlocal][k] = (int) ubuf(buf[m++]).i; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); + // perform the pack with adjusted values - atom->nlocal++; - return m; -} + int n = AtomVec::pack_restart(i,buf); -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ + // restore the flagged types to their negative values -int AtomVecMolecular::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 0; - for (i = 0; i < nlocal; i++) - n += 16 + 2*num_bond[i] + 4*num_angle[i] + - 5*num_dihedral[i] + 5*num_improper[i]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_restart(int i, double *buf) -{ - int k; - - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = ubuf(molecule[i]).d; - - buf[m++] = ubuf(num_bond[i]).d; - for (k = 0; k < num_bond[i]; k++) { - buf[m++] = ubuf(MAX(bond_type[i][k],-bond_type[i][k])).d; - buf[m++] = ubuf(bond_atom[i][k]).d; + if (any_bond_negative) { + for (int m = 0; m < num_bond[i]; m++) + if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } - - buf[m++] = ubuf(num_angle[i]).d; - for (k = 0; k < num_angle[i]; k++) { - buf[m++] = ubuf(MAX(angle_type[i][k],-angle_type[i][k])).d; - buf[m++] = ubuf(angle_atom1[i][k]).d; - buf[m++] = ubuf(angle_atom2[i][k]).d; - buf[m++] = ubuf(angle_atom3[i][k]).d; + if (any_angle_negative) { + for (int m = 0; m < num_angle[i]; m++) + if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; } - - buf[m++] = ubuf(num_dihedral[i]).d; - for (k = 0; k < num_dihedral[i]; k++) { - buf[m++] = ubuf(MAX(dihedral_type[i][k],-dihedral_type[i][k])).d; - buf[m++] = ubuf(dihedral_atom1[i][k]).d; - buf[m++] = ubuf(dihedral_atom2[i][k]).d; - buf[m++] = ubuf(dihedral_atom3[i][k]).d; - buf[m++] = ubuf(dihedral_atom4[i][k]).d; + if (any_dihedral_negative) { + for (int m = 0; m < num_dihedral[i]; m++) + if (dihedral_negative[m]) dihedral_type[i][m] = -dihedral_type[i][m]; } - - buf[m++] = ubuf(num_improper[i]).d; - for (k = 0; k < num_improper[i]; k++) { - buf[m++] = ubuf(MAX(improper_type[i][k],-improper_type[i][k])).d; - buf[m++] = ubuf(improper_atom1[i][k]).d; - buf[m++] = ubuf(improper_atom2[i][k]).d; - buf[m++] = ubuf(improper_atom3[i][k]).d; - buf[m++] = ubuf(improper_atom4[i][k]).d; + if (any_improper_negative) { + for (int m = 0; m < num_improper[i]; m++) + if (improper_negative[m]) improper_type[i][m] = -improper_type[i][m]; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; + return n; } /* ---------------------------------------------------------------------- unpack data for one atom from restart file including extra quantities + initialize other atom quantities ------------------------------------------------------------------------- */ int AtomVecMolecular::unpack_restart(double *buf) { - int k; - - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - - num_bond[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_bond[nlocal]; k++) { - bond_type[nlocal][k] = (int) ubuf(buf[m++]).i; - bond_atom[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_angle[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_angle[nlocal]; k++) { - angle_type[nlocal][k] = (int) ubuf(buf[m++]).i; - angle_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - angle_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_dihedral[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_dihedral[nlocal]; k++) { - dihedral_type[nlocal][k] = (int) ubuf(buf[m++]).i; - dihedral_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - dihedral_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - num_improper[nlocal] = (int) ubuf(buf[m++]).i; - for (k = 0; k < num_improper[nlocal]; k++) { - improper_type[nlocal][k] = (int) ubuf(buf[m++]).i; - improper_atom1[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom2[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom3[nlocal][k] = (tagint) ubuf(buf[m++]).i; - improper_atom4[nlocal][k] = (tagint) ubuf(buf[m++]).i; - } - - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecMolecular::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - molecule[nlocal] = 0; - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - num_dihedral[nlocal] = 0; - num_improper[nlocal] = 0; - nspecial[nlocal][0] = nspecial[nlocal][1] = nspecial[nlocal][2] = 0; + AtomVec::unpack_restart(buf); + int ilocal = atom->nlocal-1; - atom->nlocal++; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecMolecular::data_atom(double *coord, imageint imagetmp, - char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - num_dihedral[nlocal] = 0; - num_improper[nlocal] = 0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -int AtomVecMolecular::data_atom_hybrid(int nlocal, char **values) +void AtomVecMolecular::data_atom(double *coord, imageint imagetmp, char **values) { - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - - num_bond[nlocal] = 0; - num_angle[nlocal] = 0; - num_dihedral[nlocal] = 0; - num_improper[nlocal] = 0; - - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecMolecular::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(type[i]).d; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecMolecular::pack_data_hybrid(int i, double *buf) -{ - buf[0] = ubuf(molecule[i]).d; - return 1; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecMolecular::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i, - buf[i][3],buf[i][4],buf[i][5], - (int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i, - (int) ubuf(buf[i][8]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecMolecular::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT,(tagint) ubuf(buf[0]).i); - return 1; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecMolecular::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("nspecial")) bytes += memory->usage(nspecial,nmax,3); - if (atom->memcheck("special")) - bytes += memory->usage(special,nmax,atom->maxspecial); - - if (atom->memcheck("num_bond")) bytes += memory->usage(num_bond,nmax); - if (atom->memcheck("bond_type")) - bytes += memory->usage(bond_type,nmax,atom->bond_per_atom); - if (atom->memcheck("bond_atom")) - bytes += memory->usage(bond_atom,nmax,atom->bond_per_atom); - - if (atom->memcheck("num_angle")) bytes += memory->usage(num_angle,nmax); - if (atom->memcheck("angle_type")) - bytes += memory->usage(angle_type,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom1")) - bytes += memory->usage(angle_atom1,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom2")) - bytes += memory->usage(angle_atom2,nmax,atom->angle_per_atom); - if (atom->memcheck("angle_atom3")) - bytes += memory->usage(angle_atom3,nmax,atom->angle_per_atom); - - if (atom->memcheck("num_dihedral")) bytes += memory->usage(num_dihedral,nmax); - if (atom->memcheck("dihedral_type")) - bytes += memory->usage(dihedral_type,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom1")) - bytes += memory->usage(dihedral_atom1,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom2")) - bytes += memory->usage(dihedral_atom2,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom3")) - bytes += memory->usage(dihedral_atom3,nmax,atom->dihedral_per_atom); - if (atom->memcheck("dihedral_atom4")) - bytes += memory->usage(dihedral_atom4,nmax,atom->dihedral_per_atom); - - if (atom->memcheck("num_improper")) bytes += memory->usage(num_improper,nmax); - if (atom->memcheck("improper_type")) - bytes += memory->usage(improper_type,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom1")) - bytes += memory->usage(improper_atom1,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom2")) - bytes += memory->usage(improper_atom2,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom3")) - bytes += memory->usage(improper_atom3,nmax,atom->improper_per_atom); - if (atom->memcheck("improper_atom4")) - bytes += memory->usage(improper_atom4,nmax,atom->improper_per_atom); + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; - return bytes; + atom->num_bond[ilocal] = 0; + atom->num_angle[ilocal] = 0; + atom->num_dihedral[ilocal] = 0; + atom->num_improper[ilocal] = 0; + atom->nspecial[ilocal][0] = 0; + atom->nspecial[ilocal][1] = 0; + atom->nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_molecular.h b/src/MOLECULE/atom_vec_molecular.h index 19104c3987..cba6d1b480 100644 --- a/src/MOLECULE/atom_vec_molecular.h +++ b/src/MOLECULE/atom_vec_molecular.h @@ -27,55 +27,14 @@ namespace LAMMPS_NS { class AtomVecMolecular : public AtomVec { public: AtomVecMolecular(class LAMMPS *); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); + ~AtomVecMolecular(); int pack_restart(int, double *); int unpack_restart(double *); - void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - tagint *molecule; - int **nspecial; - tagint **special; - int *num_bond; - int **bond_type; - tagint **bond_atom; - int *num_angle; - int **angle_type; - tagint **angle_atom1,**angle_atom2,**angle_atom3; - int *num_dihedral; - int **dihedral_type; - tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; - int *num_improper; - int **improper_type; - tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; + int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; + int *bond_negative,*angle_negative,*dihedral_negative,*improper_negative; }; } @@ -85,13 +44,4 @@ class AtomVecMolecular : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/MOLECULE/atom_vec_template.cpp b/src/MOLECULE/atom_vec_template.cpp index c9ccfc6d2b..31d9af4caf 100644 --- a/src/MOLECULE/atom_vec_template.cpp +++ b/src/MOLECULE/atom_vec_template.cpp @@ -31,16 +31,27 @@ AtomVecTemplate::AtomVecTemplate(LAMMPS *lmp) : AtomVec(lmp) molecular = 2; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 9; - size_velocity = 3; - size_data_atom = 8; - size_data_vel = 4; - xcol_data = 6; - atom->molecule_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 the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) "molecule molindex molatom"; + fields_copy = (char *) "molecule molindex molatom"; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = (char *) "molecule molindex molatom"; + fields_border_vel = (char *) "molecule molindex molatom"; + fields_exchange = (char *) "molecule molindex molatom"; + fields_restart = (char *) "molecule molindex molatom"; + fields_create = (char *) "molecule molindex molatom"; + fields_data_atom = (char *) "id molecule molindex molatom type x"; + fields_data_vel = NULL; + + setup_fields(); } /* ---------------------------------------------------------------------- @@ -85,786 +96,35 @@ void AtomVecTemplate::process_args(int narg, char **arg) } } -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecTemplate::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - molindex = memory->grow(atom->molindex,nmax,"atom:molindex"); - molatom = memory->grow(atom->molatom,nmax,"atom:molatom"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecTemplate::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - molecule = atom->molecule; - molindex = atom->molindex; molatom = atom->molatom; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecTemplate::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - molecule[j] = molecule[i]; - molindex[j] = molindex[i]; - molatom[j] = molatom[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTemplate::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTemplate::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTemplate::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = ubuf(molindex[j]).d; - buf[m++] = ubuf(molatom[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = ubuf(molindex[j]).d; - buf[m++] = ubuf(molatom[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = ubuf(molindex[j]).d; - buf[m++] = ubuf(molatom[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = ubuf(molindex[j]).d; - buf[m++] = ubuf(molatom[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = ubuf(molindex[j]).d; - buf[m++] = ubuf(molatom[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = ubuf(molindex[j]).d; - buf[m++] = ubuf(molatom[j]).d; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTemplate::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - molindex[i] = (int) ubuf(buf[m++]).i; - molatom[i] = (int) ubuf(buf[m++]).i; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTemplate::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - molindex[i] = (int) ubuf(buf[m++]).i; - molatom[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - molecule[i] = (tagint) ubuf(buf[m++]).i; - molindex[i] = (int) ubuf(buf[m++]).i; - molatom[i] = (int) ubuf(buf[m++]).i; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = ubuf(molindex[i]).d; - buf[m++] = ubuf(molatom[i]).d; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTemplate::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - molindex[nlocal] = (int) ubuf(buf[m++]).i; - molatom[nlocal] = (int) ubuf(buf[m++]).i; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecTemplate::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 14 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = ubuf(molindex[i]).d; - buf[m++] = ubuf(molatom[i]).d; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecTemplate::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - molindex[nlocal] = (int) ubuf(buf[m++]).i; - molatom[nlocal] = (int) ubuf(buf[m++]).i; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - /* ---------------------------------------------------------------------- create one atom of itype at coord - set other values to defaults + modify what default AtomVec::create_atom() just created ------------------------------------------------------------------------- */ void AtomVecTemplate::create_atom(int itype, double *coord) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - molecule[nlocal] = 0; - molindex[nlocal] = -1; - molatom[nlocal] = -1; + AtomVec::create_atom(itype,coord); - atom->nlocal++; + int ilocal = atom->nlocal-1; + atom->molindex[ilocal] = -1; + atom->molatom[ilocal] = -1; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + error check what default AtomVec::data_atom() just unpacked ------------------------------------------------------------------------- */ void AtomVecTemplate::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); + AtomVec::data_atom(coord,imagetmp,values); - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - if (tag[nlocal] <= 0) - error->one(FLERR,"Invalid atom ID in Atoms section of data file"); + int ilocal = atom->nlocal-1; + int molindex = atom->molindex[ilocal]; + int molatom = atom->molatom[ilocal]; - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - molindex[nlocal] = utils::inumeric(FLERR,values[2],true,lmp) - 1; - molatom[nlocal] = utils::inumeric(FLERR,values[3],true,lmp) - 1; - - if (molindex[nlocal] < 0 || molindex[nlocal] >= nset) + if (molindex < 0 || molindex >= nset) error->one(FLERR,"Invalid template index in Atoms section of data file"); - if (molatom[nlocal] < 0 || - molatom[nlocal] >= onemols[molindex[nlocal]]->natoms) + if (molatom < 0 || molatom >= onemols[molindex]->natoms) error->one(FLERR,"Invalid template atom in Atoms section of data file"); - - type[nlocal] = utils::inumeric(FLERR,values[4],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecTemplate::data_atom_hybrid(int nlocal, char **values) -{ - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molindex[nlocal] = utils::inumeric(FLERR,values[1],true,lmp) - 1; - molatom[nlocal] = utils::inumeric(FLERR,values[2],true,lmp) - 1; - return 3; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecTemplate::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(molindex[i]+1).d; - buf[i][3] = ubuf(molatom[i]+1).d; - buf[i][4] = ubuf(type[i]).d; - buf[i][5] = x[i][0]; - buf[i][6] = x[i][1]; - buf[i][7] = x[i][2]; - buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecTemplate::pack_data_hybrid(int i, double *buf) -{ - buf[0] = ubuf(molecule[i]).d; - buf[1] = ubuf(molindex[i]+1).d; - buf[2] = ubuf(molatom[i]+1).d; - return 3; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecTemplate::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %d %d %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i,(int) ubuf(buf[i][3]).i, - (int) ubuf(buf[i][4]).i, - buf[i][5],buf[i][6],buf[i][7], - (int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i, - (int) ubuf(buf[i][10]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecTemplate::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT " %d %d", - (tagint) ubuf(buf[0]).i,(int) ubuf(buf[1]).i,(int) ubuf(buf[2]).i); - return 3; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecTemplate::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("molindex")) bytes += memory->usage(molindex,nmax); - if (atom->memcheck("molatom")) bytes += memory->usage(molatom,nmax); - - return bytes; } diff --git a/src/MOLECULE/atom_vec_template.h b/src/MOLECULE/atom_vec_template.h index eee7fa9723..59a1386f2d 100644 --- a/src/MOLECULE/atom_vec_template.h +++ b/src/MOLECULE/atom_vec_template.h @@ -27,44 +27,9 @@ namespace LAMMPS_NS { class AtomVecTemplate : public AtomVec { public: AtomVecTemplate(class LAMMPS *); - virtual ~AtomVecTemplate() {} void process_args(int, char **); - void grow(int); - void grow_reset(); - void copy(int, int, int); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); void create_atom(int, double *); - void data_atom(double *, tagint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - - protected: - tagint *tag; - int *type,*mask; - tagint *image; - double **x,**v,**f; - tagint *molecule; - int *molindex,*molatom; + void data_atom(double *, imageint, char **); }; } @@ -88,15 +53,6 @@ E: Atom style template molecule must have atom types The defined molecule(s) does not specify atom types. -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom ID in Atoms section of data file - -Atom IDs must be positive integers. - E: Invalid template index in Atoms section of data file The template indices must be between 1 to N, where N is the number of @@ -107,8 +63,4 @@ E: Invalid template atom in Atoms section of data file The atom indices must be between 1 to N, where N is the number of atoms in the template molecule the atom belongs to. -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp index 3e3312bf01..29c4cb0d83 100644 --- a/src/PERI/atom_vec_peri.cpp +++ b/src/PERI/atom_vec_peri.cpp @@ -19,14 +19,9 @@ #include #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" #include "citeme.h" #include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -49,859 +44,67 @@ AtomVecPeri::AtomVecPeri(LAMMPS *lmp) : AtomVec(lmp) molecular = 0; - comm_x_only = 0; - comm_f_only = 1; - size_forward = 4; - size_reverse = 3; - size_border = 12; - size_velocity = 3; - size_data_atom = 7; - size_data_vel = 4; - xcol_data = 5; - + atom->rmass_flag = 1; atom->peri_flag = 1; - atom->vfrac_flag = atom->rmass_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecPeri::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - vfrac = memory->grow(atom->vfrac,nmax,"atom:vfrac"); - rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); - s0 = memory->grow(atom->s0,nmax,"atom:s0"); - x0 = memory->grow(atom->x0,nmax,3,"atom:x0"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecPeri::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - vfrac = atom->vfrac; rmass = atom->rmass; - s0 = atom->s0; x0 = atom->x0; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecPeri::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - vfrac[j] = vfrac[i]; - rmass[j] = rmass[i]; - s0[j] = s0[i]; - x0[j][0] = x0[i][0]; - x0[j][1] = x0[i][1]; - x0[j][2] = x0[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) - -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = s0[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = s0[j]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) - -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = s0[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = s0[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = s0[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = s0[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecPeri::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - s0[i] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecPeri::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - s0[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - s0[i] = buf[m++]; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecPeri::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = vfrac[j]; - buf[m++] = rmass[j]; - buf[m++] = s0[j]; - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = vfrac[j]; - buf[m++] = rmass[j]; - buf[m++] = s0[j]; - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = vfrac[j]; - buf[m++] = rmass[j]; - buf[m++] = s0[j]; - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = vfrac[j]; - buf[m++] = rmass[j]; - buf[m++] = s0[j]; - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = vfrac[j]; - buf[m++] = rmass[j]; - buf[m++] = s0[j]; - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = vfrac[j]; - buf[m++] = rmass[j]; - buf[m++] = s0[j]; - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ + atom->vfrac_flag = 1; -void AtomVecPeri::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - vfrac[i] = buf[m++]; - rmass[i] = buf[m++]; - s0[i] = buf[m++]; - x0[i][0] = buf[m++]; - x0[i][1] = buf[m++]; - x0[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecPeri::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - vfrac[i] = buf[m++]; - rmass[i] = buf[m++]; - s0[i] = buf[m++]; - x0[i][0] = buf[m++]; - x0[i][1] = buf[m++]; - x0[i][2] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } + fields_grow = (char *) "rmass vfrac s0 x0"; + fields_copy = (char *) "rmass vfrac s0 x0"; + fields_comm = (char *) "s0"; + fields_comm_vel = (char *) "s0"; + fields_reverse = NULL; + fields_border = (char *) "rmass vfrac s0 x0"; + fields_border_vel = (char *) "rmass vfrac s0 x0"; + fields_exchange = (char *) "rmass vfrac s0 x0"; + fields_restart = (char *) "rmass vfrac s0 x0"; + fields_create = (char *) "rmass vfrac s0 x0"; + fields_data_atom = (char *) "id type vfrac rmass x"; + fields_data_vel = (char *) "omega"; - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - vfrac[i] = buf[m++]; - rmass[i] = buf[m++]; - s0[i] = buf[m++]; - x0[i][0] = buf[m++]; - x0[i][1] = buf[m++]; - x0[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecPeri::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = vfrac[i]; - buf[m++] = rmass[i]; - buf[m++] = s0[i]; - buf[m++] = x0[i][0]; - buf[m++] = x0[i][1]; - buf[m++] = x0[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecPeri::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - vfrac[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - s0[nlocal] = buf[m++]; - x0[nlocal][0] = buf[m++]; - x0[nlocal][1] = buf[m++]; - x0[nlocal][2] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecPeri::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 17 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecPeri::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = vfrac[i]; - buf[m++] = rmass[i]; - buf[m++] = s0[i]; - buf[m++] = x0[i][0]; - buf[m++] = x0[i][1]; - buf[m++] = x0[i][2]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecPeri::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - vfrac[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - s0[nlocal] = buf[m++]; - x0[nlocal][0] = buf[m++]; - x0[nlocal][1] = buf[m++]; - x0[nlocal][2] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; + setup_fields(); } /* ---------------------------------------------------------------------- create one atom of itype at coord - set other values to defaults + modify what default AtomVec::create_atom() just created ------------------------------------------------------------------------- */ void AtomVecPeri::create_atom(int itype, double *coord) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; + AtomVec::create_atom(itype,coord); + int ilocal = atom->nlocal-1; - vfrac[nlocal] = 1.0; - rmass[nlocal] = 1.0; - s0[nlocal] = DBL_MAX; - x0[nlocal][0] = coord[0]; - x0[nlocal][1] = coord[1]; - x0[nlocal][2] = coord[2]; - - atom->nlocal++; + atom->vfrac[ilocal] = 1.0; + atom->rmass[ilocal] = 1.0; + atom->s0[ilocal] = DBL_MAX; + atom->x0[ilocal][0] = coord[0]; + atom->x0[ilocal][1] = coord[1]; + atom->x0[ilocal][2] = coord[2]; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecPeri::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - vfrac[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - rmass[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - if (rmass[nlocal] <= 0.0) error->one(FLERR,"Invalid mass value"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - s0[nlocal] = DBL_MAX; - x0[nlocal][0] = coord[0]; - x0[nlocal][1] = coord[1]; - x0[nlocal][2] = coord[2]; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecPeri::data_atom_hybrid(int nlocal, char **values) -{ - vfrac[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - rmass[nlocal] = utils::numeric(FLERR,values[1],true,lmp); - if (rmass[nlocal] <= 0.0) error->one(FLERR,"Invalid mass value"); - - s0[nlocal] = DBL_MAX; - x0[nlocal][0] = x[nlocal][0]; - x0[nlocal][1] = x[nlocal][1]; - x0[nlocal][2] = x[nlocal][2]; - - return 2; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecPeri::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = vfrac[i]; - buf[i][3] = rmass[i]; - buf[i][4] = x[i][0]; - buf[i][5] = x[i][1]; - buf[i][6] = x[i][2]; - buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecPeri::pack_data_hybrid(int i, double *buf) -{ - buf[0] = vfrac[i]; - buf[1] = rmass[i]; - return 2; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecPeri::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4],buf[i][5],buf[i][6], - (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i, - (int) ubuf(buf[i][9]).i); -} + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ + atom->s0[ilocal] = DBL_MAX; + atom->x0[ilocal][0] = coord[0]; + atom->x0[ilocal][1] = coord[1]; + atom->x0[ilocal][2] = coord[2]; -int AtomVecPeri::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e",buf[0],buf[1]); - return 2; + if (atom->rmass[ilocal] <= 0.0) + error->one(FLERR,"Invalid mass in Atoms section of data file"); } /* ---------------------------------------------------------------------- @@ -929,12 +132,14 @@ void AtomVecPeri::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { + double *vfrac = atom->vfrac; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = vfrac[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 1) { + double *s0 = atom->s0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = s0[i]; else buf[n] = 0.0; @@ -942,27 +147,3 @@ void AtomVecPeri::pack_property_atom(int index, double *buf, } } } - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecPeri::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("vfrac")) bytes += memory->usage(vfrac,nmax); - if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); - if (atom->memcheck("s0")) bytes += memory->usage(s0,nmax); - if (atom->memcheck("x0")) bytes += memory->usage(x0,nmax,3); - - return bytes; -} diff --git a/src/PERI/atom_vec_peri.h b/src/PERI/atom_vec_peri.h index 0fc30d6dc2..12ef650348 100644 --- a/src/PERI/atom_vec_peri.h +++ b/src/PERI/atom_vec_peri.h @@ -27,45 +27,10 @@ namespace LAMMPS_NS { class AtomVecPeri : public AtomVec { public: AtomVecPeri(class LAMMPS *); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); int property_atom(char *); void pack_property_atom(int, double *, int, int); - bigint memory_usage(); - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *vfrac,*rmass,*s0,**x0; }; } @@ -75,17 +40,4 @@ class AtomVecPeri : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - -E: Invalid mass value - -Self-explanatory. - */ diff --git a/src/SPIN/atom_vec_spin.cpp b/src/SPIN/atom_vec_spin.cpp index ad1384ffd2..135f8936a1 100644 --- a/src/SPIN/atom_vec_spin.cpp +++ b/src/SPIN/atom_vec_spin.cpp @@ -27,13 +27,6 @@ #include #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "error.h" -#include "fix.h" -#include "memory.h" -#include "modify.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -45,908 +38,45 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) mass_type = 1; forceclearflag = 1; - comm_x_only = 0; - comm_f_only = 0; - size_forward = 7; - size_reverse = 9; - size_border = 10; - size_velocity = 3; - size_data_atom = 9; - size_data_vel = 4; - xcol_data = 4; - atom->sp_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecSpin::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file - // allocating mech. quantities - - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - // allocating mag. quantities - - sp = memory->grow(atom->sp,nmax,4,"atom:sp"); - fm = memory->grow(atom->fm,nmax*comm->nthreads,3,"atom:fm"); - fm_long = memory->grow(atom->fm_long,nmax*comm->nthreads,3,"atom:fm_long"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ + fields_grow = (char *) "sp fm fm_long"; + fields_copy = (char *) "sp"; + fields_comm = (char *) "sp"; + fields_comm_vel = (char *) "sp"; + fields_reverse = (char *) "fm fm_long"; + fields_border = (char *) "sp"; + fields_border_vel = (char *) "sp"; + fields_exchange = (char *) "sp"; + fields_restart = (char *) "sp"; + fields_create = (char *) "sp"; + fields_data_atom = (char *) "id type x sp"; + fields_data_vel = (char *) "omega"; -void AtomVecSpin::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - sp = atom->sp; fm = atom->fm; fm_long = atom->fm_long; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecSpin::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - sp[j][0] = sp[i][0]; - sp[j][1] = sp[i][1]; - sp[j][2] = sp[i][2]; - sp[j][3] = sp[i][3]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = sp[j][3]; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSpin::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - sp[i][0] = buf[m++]; - sp[i][1] = buf[m++]; - sp[i][2] = buf[m++]; - sp[i][3] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSpin::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - sp[i][0] = buf[m++]; - sp[i][1] = buf[m++]; - sp[i][2] = buf[m++]; - sp[i][3] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - sp[i][3] = buf[m++]; - sp[i][0] = buf[m++]; - sp[i][1] = buf[m++]; - sp[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = fm[i][0]; - buf[m++] = fm[i][1]; - buf[m++] = fm[i][2]; - buf[m++] = fm_long[i][0]; - buf[m++] = fm_long[i][1]; - buf[m++] = fm_long[i][2]; - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSpin::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - fm[j][0] += buf[m++]; - fm[j][1] += buf[m++]; - fm[j][2] += buf[m++]; - fm_long[j][0] += buf[m++]; - fm_long[j][1] += buf[m++]; - fm_long[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - buf[m++] = sp[j][3]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = sp[j][3]; - buf[m++] = sp[j][0]; - buf[m++] = sp[j][1]; - buf[m++] = sp[j][2]; - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSpin::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - sp[i][0] = buf[m++]; - sp[i][1] = buf[m++]; - sp[i][2] = buf[m++]; - sp[i][3] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); - -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSpin::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - sp[i][0] = buf[m++]; - sp[i][1] = buf[m++]; - sp[i][2] = buf[m++]; - sp[i][3] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); - -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - sp[i][3] = buf[m++]; - sp[i][0] = buf[m++]; - sp[i][1] = buf[m++]; - sp[i][2] = buf[m++]; - } - - return m; -} - -/* ---------------------------------------------------------------------- - pack all atom quantities for shipping to another proc - xyz must be 1st 3 values, so that comm::exchange can test on them -------------------------------------------------------------------------- */ - -int AtomVecSpin::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = sp[i][0]; - buf[m++] = sp[i][1]; - buf[m++] = sp[i][2]; - buf[m++] = sp[i][3]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSpin::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - sp[nlocal][0] = buf[m++]; - sp[nlocal][1] = buf[m++]; - sp[nlocal][2] = buf[m++]; - sp[nlocal][3] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecSpin::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 15 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecSpin::pack_restart(int i, double *buf) -{ - int m = 1; - - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = sp[i][0]; - buf[m++] = sp[i][1]; - buf[m++] = sp[i][2]; - buf[m++] = sp[i][3]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecSpin::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - sp[nlocal][0] = buf[m++]; - sp[nlocal][1] = buf[m++]; - sp[nlocal][2] = buf[m++]; - sp[nlocal][3] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecSpin::create_atom(int itype, double *coord) -{ - - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - sp[nlocal][0] = 0.0; - sp[nlocal][1] = 0.0; - sp[nlocal][2] = 0.0; - sp[nlocal][3] = 0.0; - - atom->nlocal++; + setup_fields(); } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecSpin::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - sp[nlocal][3] = utils::numeric(FLERR,values[2],true,lmp); - sp[nlocal][0] = utils::numeric(FLERR,values[6],true,lmp); - sp[nlocal][1] = utils::numeric(FLERR,values[7],true,lmp); - sp[nlocal][2] = utils::numeric(FLERR,values[8],true,lmp); - double inorm = 1.0/sqrt(sp[nlocal][0]*sp[nlocal][0] + - sp[nlocal][1]*sp[nlocal][1] + - sp[nlocal][2]*sp[nlocal][2]); - sp[nlocal][0] *= inorm; - sp[nlocal][1] *= inorm; - sp[nlocal][2] *= inorm; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecSpin::data_atom_hybrid(int nlocal, char **values) -{ - - sp[nlocal][0] = utils::numeric(FLERR,values[0],true,lmp); - sp[nlocal][1] = utils::numeric(FLERR,values[1],true,lmp); - sp[nlocal][2] = utils::numeric(FLERR,values[2],true,lmp); - double inorm = 1.0/sqrt(sp[nlocal][0]*sp[nlocal][0] + - sp[nlocal][1]*sp[nlocal][1] + - sp[nlocal][2]*sp[nlocal][2]); - sp[nlocal][0] *= inorm; - sp[nlocal][1] *= inorm; - sp[nlocal][2] *= inorm; - sp[nlocal][3] = utils::numeric(FLERR,values[3],true,lmp); - - return 4; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; -void AtomVecSpin::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = sp[i][3]; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = sp[i][0]; - buf[i][7] = sp[i][1]; - buf[i][8] = sp[i][2]; - buf[i][9] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][11] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecSpin::pack_data_hybrid(int i, double *buf) -{ - buf[0] = sp[i][3]; - buf[1] = sp[i][0]; - buf[2] = sp[i][1]; - buf[3] = sp[i][2]; - return 4; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecSpin::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT \ - " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e " - "%-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4], - buf[i][5],buf[i][6],buf[i][7],buf[i][8], - (int) ubuf(buf[i][9]).i,(int) ubuf(buf[i][10]).i, - (int) ubuf(buf[i][11]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecSpin::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2],buf[3]); - return 4; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecSpin::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("sp")) bytes += memory->usage(sp,nmax,4); - if (atom->memcheck("fm")) bytes += memory->usage(fm,nmax*comm->nthreads,3); - if (atom->memcheck("fm_long")) bytes += memory->usage(fm_long,nmax*comm->nthreads,3); - - return bytes; + double *sp = atom->sp[ilocal]; + double inorm = 1.0/sqrt(sp[0]*sp[0] + sp[1]*sp[1] + sp[2]*sp[2]); + sp[0] *= inorm; + sp[1] *= inorm; + sp[2] *= inorm; } /* ---------------------------------------------------------------------- @@ -959,5 +89,3 @@ void AtomVecSpin::force_clear(int /*n*/, size_t nbytes) memset(&atom->fm[0][0],0,3*nbytes); memset(&atom->fm_long[0][0],0,3*nbytes); } - - diff --git a/src/SPIN/atom_vec_spin.h b/src/SPIN/atom_vec_spin.h index 6ce2c9dc7d..ca92cccc2e 100644 --- a/src/SPIN/atom_vec_spin.h +++ b/src/SPIN/atom_vec_spin.h @@ -27,53 +27,8 @@ namespace LAMMPS_NS { class AtomVecSpin : public AtomVec { public: AtomVecSpin(class LAMMPS *); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - - // clear magnetic and mechanic forces - void force_clear(int, size_t); - - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; // lattice quantities - - // spin quantities - double **sp; // sp[i][0-2] direction of the spin i - // sp[i][3] atomic magnetic moment of the spin i - double **fm; // fm[i][0-2] direction of magnetic precession - double **fm_long; // storage of long-range spin prec. components }; } @@ -83,13 +38,4 @@ class AtomVecSpin : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/atom.cpp b/src/atom.cpp index de5d30930a..7f1a5a6022 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -44,9 +44,11 @@ using namespace LAMMPS_NS; using namespace MathConst; #define DELTA 1 -#define DELTA_MEMSTR 1024 +#define DELTA_PERATOM 64 #define EPSILON 1.0e-6 +enum{DOUBLE,INT,BIGINT}; + /* ---------------------------------------------------------------------- */ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) @@ -66,6 +68,11 @@ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) binhead = NULL; next = permute = NULL; + // data structure with info on per-atom vectors/arrays + + nperatom = maxperatom = 0; + peratom = NULL; + // initialize atom arrays // customize by adding new array @@ -193,6 +200,10 @@ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) pdscale = 1.0; + // initialize peratom data structure + + peratom_create(); + // ntype-length arrays mass = NULL; @@ -245,6 +256,12 @@ Atom::~Atom() memory->destroy(next); memory->destroy(permute); + // delete peratom data struct + + for (int i = 0; i < nperatom; i++) + delete [] peratom[i].name; + memory->sfree(peratom); + // delete atom arrays // customize by adding new array @@ -403,6 +420,175 @@ void Atom::settings(Atom *old) } } +/* ---------------------------------------------------------------------- + one-time creation of peratom data structure +------------------------------------------------------------------------- */ + +void Atom::peratom_create() +{ + for (int i = 0; i < nperatom; i++) + delete [] peratom[i].name; + memory->sfree(peratom); + + peratom = NULL; + nperatom = maxperatom = 0; + + // customize: add new peratom variables here, order does not matter + // register tagint & imageint variables as INT or BIGINT + + int tagintsize = INT; + if (sizeof(tagint) == 8) tagintsize = BIGINT; + int imageintsize = INT; + if (sizeof(imageint) == 8) imageintsize = BIGINT; + + add_peratom("id",&tag,tagintsize,0); + add_peratom("type",&type,INT,0); + add_peratom("mask",&mask,INT,0); + add_peratom("image",&image,imageintsize,0); + + add_peratom("x",&x,DOUBLE,3); + add_peratom("v",&v,DOUBLE,3); + add_peratom("f",&f,DOUBLE,3,1); // set per-thread flag + + add_peratom("rmass",&rmass,DOUBLE,0); + add_peratom("q",&q,DOUBLE,0); + add_peratom("mu",&mu,DOUBLE,4); + add_peratom("mu3",&mu,DOUBLE,3); // just first 3 values of mu[4] + + // finite size particles + + add_peratom("radius",&radius,DOUBLE,0); + add_peratom("omega",&omega,DOUBLE,3); + add_peratom("amgmom",&angmom,DOUBLE,3); + add_peratom("torque",&torque,DOUBLE,3,1); // set per-thread flag + + add_peratom("ellipsoid",&ellipsoid,INT,0); + add_peratom("line",&line,INT,0); + add_peratom("tri",&tri,INT,0); + add_peratom("body",&body,INT,0); + + // MOLECULE package + + add_peratom("molecule",&molecule,tagintsize,0); + add_peratom("molindex",&molindex,INT,0); + add_peratom("molatom",&molatom,INT,0); + + add_peratom("nspecial",&nspecial,INT,3); + add_peratom_vary("special",&special,tagintsize,&maxspecial,&nspecial,3); + + add_peratom("num_bond",&num_bond,INT,0); + add_peratom_vary("bond_type",&bond_type,INT,&bond_per_atom,&num_bond); + add_peratom_vary("bond_atom",&bond_atom,tagintsize,&bond_per_atom,&num_bond); + + add_peratom("num_angle",&num_angle,INT,0); + add_peratom_vary("angle_type",&angle_type,INT,&angle_per_atom,&num_angle); + add_peratom_vary("angle_atom1",&angle_atom1,tagintsize, + &angle_per_atom,&num_angle); + add_peratom_vary("angle_atom2",&angle_atom2,tagintsize, + &angle_per_atom,&num_angle); + add_peratom_vary("angle_atom3",&angle_atom3,tagintsize, + &angle_per_atom,&num_angle); + + add_peratom("num_dihedral",&num_dihedral,INT,0); + add_peratom_vary("dihedral_type",&dihedral_type,INT, + &dihedral_per_atom,&num_dihedral); + add_peratom_vary("dihedral_atom1",&dihedral_atom1,tagintsize, + &dihedral_per_atom,&num_dihedral); + add_peratom_vary("dihedral_atom2",&dihedral_atom2,tagintsize, + &dihedral_per_atom,&num_dihedral); + add_peratom_vary("dihedral_atom3",&dihedral_atom3,tagintsize, + &dihedral_per_atom,&num_dihedral); + add_peratom_vary("dihedral_atom4",&dihedral_atom4,tagintsize, + &dihedral_per_atom,&num_dihedral); + + add_peratom("num_improper",&num_improper,INT,0); + add_peratom_vary("improper_type",&improper_type,INT, + &improper_per_atom,&num_improper); + add_peratom_vary("improper_atom1",&improper_atom1,tagintsize, + &improper_per_atom,&num_improper); + add_peratom_vary("improper_atom2",&improper_atom2,tagintsize, + &improper_per_atom,&num_improper); + add_peratom_vary("improper_atom3",&improper_atom3,tagintsize, + &improper_per_atom,&num_improper); + add_peratom_vary("improper_atom4",&improper_atom4,tagintsize, + &improper_per_atom,&num_improper); + + // PERI package + + add_peratom("vfrac",&vfrac,DOUBLE,0); + add_peratom("s0",&s0,DOUBLE,0); + add_peratom("x0",&x0,DOUBLE,3); + + // SPIN package + + add_peratom("sp",&sp,DOUBLE,4); + add_peratom("fm",&fm,DOUBLE,3,1); + add_peratom("fm_long",&fm_long,DOUBLE,3,1); +} + +/* ---------------------------------------------------------------------- + add info for a single per-atom vector/array to PerAtom data struct + cols = 0: per-atom vector + cols = N: static per-atom array with N columns + use add_peratom_vary() when column count varies per atom +------------------------------------------------------------------------- */ + +void Atom::add_peratom(const char *name, void *address, + int datatype, int cols, int threadflag) +{ + if (nperatom == maxperatom) { + maxperatom += DELTA_PERATOM; + peratom = (PerAtom *) + memory->srealloc(peratom,maxperatom*sizeof(PerAtom),"atom:peratom"); + } + + int n = strlen(name) + 1; + peratom[nperatom].name = new char[n]; + strcpy(peratom[nperatom].name,name); + peratom[nperatom].address = address; + peratom[nperatom].datatype = datatype; + peratom[nperatom].cols = cols; + peratom[nperatom].threadflag = threadflag; + peratom[nperatom].address_length = NULL; + + nperatom++; +} + +/* ---------------------------------------------------------------------- + add info for a single per-atom array to PerAtom data struct + cols = address of int variable with max columns per atom + for collength = 0: + length = address of peratom vector with column count per atom + e.g. num_bond + for collength = N: + length = address of peratom array with column count per atom + collength = index of column (1 to N) in peratom array with count + e.g. nspecial +------------------------------------------------------------------------- */ + +void Atom::add_peratom_vary(const char *name, void *address, + int datatype, int *cols, void *length, int collength) +{ + if (nperatom == maxperatom) { + maxperatom += DELTA_PERATOM; + peratom = (PerAtom *) + memory->srealloc(peratom,maxperatom*sizeof(PerAtom),"atom:peratom"); + } + + int n = strlen(name) + 1; + peratom[nperatom].name = new char[n]; + strcpy(peratom[nperatom].name,name); + peratom[nperatom].address = address; + peratom[nperatom].datatype = datatype; + peratom[nperatom].cols = -1; + peratom[nperatom].threadflag = 0; + peratom[nperatom].address_maxcols = cols; + peratom[nperatom].address_length = length; + peratom[nperatom].collength = collength; + + nperatom++; +} + /* ---------------------------------------------------------------------- create an AtomVec style called from lammps.cpp, input script, restart file, replicate @@ -2296,11 +2482,7 @@ void *Atom::extract(char *name) bigint Atom::memory_usage() { - memlength = DELTA_MEMSTR; - memory->create(memstr,memlength,"atom:memstr"); - memstr[0] = '\0'; bigint bytes = avec->memory_usage(); - memory->destroy(memstr); bytes += max_same*sizeof(int); if (map_style == 1) @@ -2316,31 +2498,3 @@ bigint Atom::memory_usage() return bytes; } - -/* ---------------------------------------------------------------------- - accumulate per-atom vec names in memstr, padded by spaces - return 1 if padded str is not already in memlist, else 0 -------------------------------------------------------------------------- */ - -int Atom::memcheck(const char *str) -{ - int n = strlen(str) + 3; - char *padded = new char[n]; - strcpy(padded," "); - strcat(padded,str); - strcat(padded," "); - - if (strstr(memstr,padded)) { - delete [] padded; - return 0; - } - - if ((int)strlen(memstr) + n >= memlength) { - memlength += DELTA_MEMSTR; - memory->grow(memstr,memlength,"atom:memstr"); - } - - strcat(memstr,padded); - delete [] padded; - return 1; -} diff --git a/src/atom.h b/src/atom.h index 81f643c007..6cc5dff72a 100644 --- a/src/atom.h +++ b/src/atom.h @@ -38,6 +38,8 @@ class Atom : protected Pointers { bigint nlines; // number of lines bigint ntris; // number of triangles bigint nbodies; // number of bodies + + // system properties bigint nbonds,nangles,ndihedrals,nimpropers; int ntypes,nbondtypes,nangletypes,ndihedraltypes,nimpropertypes; @@ -49,54 +51,67 @@ class Atom : protected Pointers { int nfirst; // # of atoms in first group on this proc char *firstgroupname; // group-ID to store first, NULL if unset - // per-atom arrays - // customize by adding new array + // -------------------------------------------------------------------- + // 1st customization section: customize by adding new per-atom variable + // per-atom vectors and arrays tagint *tag; int *type,*mask; imageint *image; double **x,**v,**f; - tagint *molecule; - int *molindex,*molatom; - + double *rmass; double *q,**mu; + + // finite-size particles + + double *radius; double **omega,**angmom,**torque; - double *radius,*rmass; int *ellipsoid,*line,*tri,*body; - // SPIN package + // MOLECULE package - double **sp; - double **fm; - double **fm_long; + tagint *molecule; + int *molindex,*molatom; + + int **nspecial; // 0,1,2 = cumulative # of 1-2,1-3,1-4 neighs + tagint **special; // IDs of 1-2,1-3,1-4 neighs of each atom + int maxspecial; // special[nlocal][maxspecial] + + int *num_bond; + int **bond_type; + tagint **bond_atom; + + int *num_angle; + int **angle_type; + tagint **angle_atom1,**angle_atom2,**angle_atom3; + + int *num_dihedral; + int **dihedral_type; + tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; + + int *num_improper; + int **improper_type; + tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; // PERI package double *vfrac,*s0; double **x0; - // USER-EFF and USER-AWPMD packages + // SPIN package + + double **sp; + double **fm; + double **fm_long; + + // USER-AWPMD and USER_EFF packages int *spin; double *eradius,*ervel,*erforce,*ervelforce; double *cs,*csforce,*vforce; int *etag; - // USER-SPH package - - double *rho,*drho,*e,*de,*cv; - double **vest; - - // USER-SMD package - - double *contact_radius; - double **smd_data_9; - double **smd_stress; - double *eff_plastic_strain; - double *eff_plastic_strain_rate; - double *damage; - // USER-DPD package double *uCond,*uMech,*uChem,*uCGnew,*uCG; @@ -111,37 +126,24 @@ class Atom : protected Pointers { double *edpd_cv; // heat capacity int cc_species; - // molecular info - - int **nspecial; // 0,1,2 = cumulative # of 1-2,1-3,1-4 neighs - tagint **special; // IDs of 1-2,1-3,1-4 neighs of each atom - int maxspecial; // special[nlocal][maxspecial] - - int *num_bond; - int **bond_type; - tagint **bond_atom; - - int *num_angle; - int **angle_type; - tagint **angle_atom1,**angle_atom2,**angle_atom3; - - int *num_dihedral; - int **dihedral_type; - tagint **dihedral_atom1,**dihedral_atom2,**dihedral_atom3,**dihedral_atom4; + // USER-SMD package - int *num_improper; - int **improper_type; - tagint **improper_atom1,**improper_atom2,**improper_atom3,**improper_atom4; + double *contact_radius; + double **smd_data_9; + double **smd_stress; + double *eff_plastic_strain; + double *eff_plastic_strain_rate; + double *damage; - // custom arrays used by fix property/atom + // USER-SPH package - int **ivector; - double **dvector; - char **iname,**dname; - int nivector,ndvector; + double *rho,*drho,*e,*de,*cv; + double **vest; - // atom style and per-atom array existence flags - // customize by adding new flag + // -------------------------------------------------------------------- + // 1st customization section: customize by adding new flag + // existence flags for per-atom vectors and arrays + // 1 if variable is used, 0 if not int sphere_flag,ellipsoid_flag,line_flag,tri_flag,body_flag; int peri_flag,electron_flag; @@ -156,7 +158,7 @@ class Atom : protected Pointers { int rho_flag,e_flag,cv_flag,vest_flag; int dpd_flag,edpd_flag,tdpd_flag; - //USER-SPIN package + // USER-SPIN package int sp_flag; @@ -175,6 +177,32 @@ class Atom : protected Pointers { double pdscale; + // end of 2 customization sections + // -------------------------------------------------------------------- + + // per-atom data struct describing all per-atom vectors/arrays + + struct PerAtom { + char *name; + void *address; + void *address_length; + int *address_maxcols; + int datatype; + int cols; + int collength; + int threadflag; + }; + + PerAtom *peratom; + int nperatom,maxperatom; + + // custom arrays used by fix property/atom + + int **ivector; + double **dvector; + char **iname,**dname; + int nivector,ndvector; + // molecule templates // each template can be a set of consecutive molecules // each with same ID (stored in molecules) @@ -221,12 +249,17 @@ class Atom : protected Pointers { typedef std::map AtomVecCreatorMap; AtomVecCreatorMap *avec_map; + // -------------------------------------------------------------------- // functions Atom(class LAMMPS *); ~Atom(); void settings(class Atom *); + void peratom_create(); + void add_peratom(const char *, void *, int, int, int threadflag=0); + void add_peratom_vary(const char *, void *, int, int *, + void *, int collength=0); void create_avec(const char *, int, char **, int); virtual class AtomVec *new_avec(const char *, int, int &); void init(); @@ -289,8 +322,10 @@ class Atom : protected Pointers { inline int get_map_size() {return map_tag_max+1;}; inline int get_map_maxarray() {return map_maxarray+1;}; + // NOTE: placeholder method until AtomVec is refactored + int memcheck(const char *) {return 1;} + bigint memory_usage(); - int memcheck(const char *); // functions for global to local ID mapping // map lookup function inlined for efficiency @@ -343,9 +378,6 @@ class Atom : protected Pointers { double bininvx,bininvy,bininvz; // inverse actual bin sizes double bboxlo[3],bboxhi[3]; // bounding box of my sub-domain - int memlength; // allocated size of memstr - char *memstr; // string of array names already counted - void setup_sort_bins(); int next_prime(int); diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index bc94e36e7a..428117f0db 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -12,18 +12,27 @@ ------------------------------------------------------------------------- */ #include "atom_vec.h" +#include #include #include "atom.h" -#include "force.h" +#include "comm.h" #include "domain.h" +#include "force.h" +#include "modify.h" +#include "fix.h" +#include "math_const.h" +#include "memory.h" #include "error.h" #include "utils.h" using namespace LAMMPS_NS; +using namespace MathConst; #define DELTA 16384 #define DELTA_BONUS 8192 +enum{DOUBLE,INT,BIGINT}; + /* ---------------------------------------------------------------------- */ AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp) @@ -39,6 +48,40 @@ AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp) nargcopy = 0; argcopy = NULL; + + nthreads = comm->nthreads; + + // peratom variables auto-included in corresponding child style fields string + // these fields cannot be specified in the fields string + // leading/trailing whitespace just facilitates matching in process_args() + + default_grow = " id type mask image x v f "; + default_copy = " id type mask image x v "; + default_comm = " x "; + default_comm_vel = " x v "; + default_reverse = " f "; + default_border = " id type mask x "; + default_border_vel = " id type mask x v "; + default_exchange = " id type mask image x v "; + default_restart = " id type mask image x v "; + default_create = " id type mask image x v "; + default_data_atom = ""; + default_data_vel = " v "; + + // initializations + + init_method(&mgrow); + init_method(&mcopy); + init_method(&mcomm); + init_method(&mcomm_vel); + init_method(&mreverse); + init_method(&mborder); + init_method(&mborder_vel); + init_method(&mexchange); + init_method(&mrestart); + init_method(&mcreate); + init_method(&mdata_atom); + init_method(&mdata_vel); } /* ---------------------------------------------------------------------- */ @@ -47,6 +90,21 @@ AtomVec::~AtomVec() { for (int i = 0; i < nargcopy; i++) delete [] argcopy[i]; delete [] argcopy; + + destroy_method(&mgrow); + destroy_method(&mcopy); + destroy_method(&mcomm); + destroy_method(&mcomm_vel); + destroy_method(&mreverse); + destroy_method(&mborder); + destroy_method(&mborder_vel); + destroy_method(&mexchange); + destroy_method(&mrestart); + destroy_method(&mcreate); + destroy_method(&mdata_atom); + destroy_method(&mdata_vel); + + delete [] threads; } /* ---------------------------------------------------------------------- @@ -87,6 +145,223 @@ void AtomVec::init() error->all(FLERR,"KOKKOS package requires a kokkos enabled atom_style"); } +/* ---------------------------------------------------------------------- + process field strings to initialize data structs for all other methods +------------------------------------------------------------------------- */ + +void AtomVec::setup_fields() +{ + int n,cols; + + if (!fields_data_atom) + error->all(FLERR,"Atom style requires fields_data_atom"); + + // process field strings + // return # of fields and matching index into atom->peratom (in Method struct) + + ngrow = process_fields(fields_grow,default_grow,&mgrow); + ncopy = process_fields(fields_copy,default_copy,&mcopy); + ncomm = process_fields(fields_comm,default_comm,&mcomm); + ncomm_vel = process_fields(fields_comm_vel,default_comm_vel,&mcomm_vel); + nreverse = process_fields(fields_reverse,default_reverse,&mreverse); + nborder = process_fields(fields_border,default_border,&mborder); + nborder_vel = process_fields(fields_border_vel,default_border_vel,&mborder_vel); + nexchange = process_fields(fields_exchange,default_exchange,&mexchange); + nrestart = process_fields(fields_restart,default_restart,&mrestart); + ncreate = process_fields(fields_create,default_create,&mcreate); + ndata_atom = process_fields(fields_data_atom,default_data_atom,&mdata_atom); + ndata_vel = process_fields(fields_data_vel,default_data_vel,&mdata_vel); + + // populate field-based data struct for each method to use + + create_method(ngrow,&mgrow); + create_method(ncopy,&mcopy); + create_method(ncomm,&mcomm); + create_method(ncomm_vel,&mcomm_vel); + create_method(nreverse,&mreverse); + create_method(nborder,&mborder); + create_method(nborder_vel,&mborder_vel); + create_method(nexchange,&mexchange); + create_method(nrestart,&mrestart); + create_method(ncreate,&mcreate); + create_method(ndata_atom,&mdata_atom); + create_method(ndata_vel,&mdata_vel); + + // create threads data struct for grow and memory_usage to use + + threads = new int[ngrow]; + for (int i = 0; i < ngrow; i++) { + Atom::PerAtom *field = &atom->peratom[mgrow.index[i]]; + if (field->threadflag) threads[i] = nthreads; + else threads[i] = 1; + } + + // set style-specific variables + // NOTE: check for others vars in atom_vec.cpp/h ?? + + if (ncomm == 0) comm_x_only = 1; + else comm_x_only = 0; + + if (nreverse == 0) comm_f_only = 1; + else comm_f_only = 0; + + size_forward = 3; + for (n = 0; n < ncomm; n++) { + cols = mcomm.cols[n]; + if (cols == 0) size_forward++; + else size_forward += cols; + } + + size_reverse = 3; + for (n = 0; n < nreverse; n++) { + cols = mreverse.cols[n]; + if (cols == 0) size_reverse++; + else size_reverse += cols; + } + + size_border = 6; + for (n = 0; n < nborder; n++) { + cols = mborder.cols[n]; + if (cols == 0) size_border++; + else size_border += cols; + } + + size_velocity = 3; + for (n = 0; n < ncomm_vel; n++) { + cols = mcomm_vel.cols[n]; + if (cols == 0) size_velocity++; + else size_velocity += cols; + } + + size_data_atom = 0; + for (n = 0; n < ndata_atom; n++) { + cols = mdata_atom.cols[n]; + if (strcmp(atom->peratom[mdata_atom.index[n]].name,"x") == 0) + xcol_data = size_data_atom + 1; + if (cols == 0) size_data_atom++; + else size_data_atom += cols; + } + + size_data_vel = 4; + for (n = 0; n < ndata_vel; n++) { + cols = mdata_vel.cols[n]; + if (cols == 0) size_data_vel++; + else size_data_vel += cols; + } +} + +/* ---------------------------------------------------------------------- + process a single field string +------------------------------------------------------------------------- */ + +int AtomVec::process_fields(char *list, const char *default_list, Method *method) +{ + int i,n; + char match[128]; + + if (list == NULL) { + method->index = NULL; + return 0; + } + + // make copy of list of fields so can tokenize it + + n = strlen(list) + 1; + char *copy = new char[n]; + strcpy(copy,list); + + int nfield = atom->count_words(copy); + int *index = new int[nfield]; + + Atom::PerAtom *peratom = atom->peratom; + int nperatom = atom->nperatom; + + nfield = 0; + char *field = strtok(copy," "); + while (field) { + + // find field in master Atom::peratom list + + for (i = 0; i < nperatom; i++) + if (strcmp(field,peratom[i].name) == 0) break; + if (i == nperatom) error->all(FLERR,"Atom_style unrecognized peratom field"); + index[nfield++] = i; + + // error if field is in default list or appears multiple times + + sprintf(match," %s ",field); + if (strstr(default_list,match)) + error->all(FLERR,"Atom_style repeat of default peratom field"); + + for (i = 0; i < nfield-1; i++) + if (index[i] == index[nfield-1]) + error->all(FLERR,"Atom_style duplicated peratom field"); + + field = strtok(NULL," "); + } + + delete [] copy; + + method->index = index; + return nfield; +} + +/* ---------------------------------------------------------------------- + create a method data structs for processing fields +------------------------------------------------------------------------- */ + +void AtomVec::create_method(int nfield, Method *method) +{ + method->pdata = new void*[nfield]; + method->datatype = new int[nfield]; + method->cols = new int[nfield]; + method->maxcols = new int*[nfield]; + method->collength = new int[nfield]; + method->plength = new void*[nfield]; + + for (int i = 0; i < nfield; i++) { + Atom::PerAtom *field = &atom->peratom[method->index[i]]; + method->pdata[i] = (void *) field->address; + method->datatype[i] = field->datatype; + method->cols[i] = field->cols; + if (method->cols[i] < 0) { + method->maxcols[i] = field->address_maxcols; + method->collength[i] = field->collength; + method->plength[i] = field->address_length; + } + } +} + +/* ---------------------------------------------------------------------- + free memory in a method data structs +------------------------------------------------------------------------- */ + +void AtomVec::init_method(Method *method) +{ + method->pdata = NULL; + method->datatype = NULL; + method->cols = NULL; + method->maxcols = NULL; + method->collength = NULL; + method->plength = NULL; + method->index = NULL; +} + +/* ---------------------------------------------------------------------- + free memory in a method data structs +------------------------------------------------------------------------- */ + +void AtomVec::destroy_method(Method *method) +{ + delete [] method->pdata; + delete [] method->datatype; + delete [] method->cols; + delete [] method->maxcols; + delete [] method->collength; + delete [] method->plength; + delete [] method->index; +} + /* ---------------------------------------------------------------------- grow nmax so it is a multiple of DELTA ------------------------------------------------------------------------- */ @@ -108,16 +383,1700 @@ int AtomVec::grow_nmax_bonus(int nmax_bonus) return nmax_bonus; } +/* ---------------------------------------------------------------------- + grow atom arrays + n = 0 grows arrays by a chunk + n > 0 allocates arrays to size n +------------------------------------------------------------------------- */ + +void AtomVec::grow(int n) +{ + int i,datatype,cols,maxcols; + void *pdata,*plength; + + if (n == 0) grow_nmax(); + else nmax = n; + atom->nmax = nmax; + if (nmax < 0 || nmax > MAXSMALLINT) + error->one(FLERR,"Per-processor system is too big"); + + tag = memory->grow(atom->tag,nmax,"atom:tag"); + type = memory->grow(atom->type,nmax,"atom:type"); + mask = memory->grow(atom->mask,nmax,"atom:mask"); + image = memory->grow(atom->image,nmax,"atom:image"); + x = memory->grow(atom->x,nmax,3,"atom:x"); + v = memory->grow(atom->v,nmax,3,"atom:v"); + f = memory->grow(atom->f,nmax*nthreads,3,"atom:f"); + + for (i = 0; i < ngrow; i++) { + pdata = mgrow.pdata[i]; + datatype = mgrow.datatype[i]; + cols = mgrow.cols[i]; + if (datatype == DOUBLE) { + if (cols == 0) + memory->grow(*((double **) pdata),nmax*threads[i],"atom:dvec"); + else if (cols > 0) + memory->grow(*((double ***) pdata),nmax*threads[i],cols,"atom:darray"); + else { + maxcols = *(mgrow.maxcols[i]); + memory->grow(*((double ***) pdata),nmax*threads[i],maxcols,"atom:darray"); + } + } else if (datatype == INT) { + if (cols == 0) + memory->grow(*((int **) pdata),nmax*threads[i],"atom:ivec"); + else if (cols > 0) + memory->grow(*((int ***) pdata),nmax*threads[i],cols,"atom:iarray"); + else { + maxcols = *(mgrow.maxcols[i]); + memory->grow(*((int ***) pdata),nmax*threads[i],maxcols,"atom:iarray"); + } + } else if (datatype == BIGINT) { + if (cols == 0) + memory->grow(*((bigint **) pdata),nmax*threads[i],"atom:bvec"); + else if (cols > 0) + memory->grow(*((bigint ***) pdata),nmax*threads[i],cols,"atom:barray"); + else { + maxcols = *(mgrow.maxcols[i]); + memory->grow(*((int ***) pdata),nmax*threads[i],maxcols,"atom:barray"); + } + } + } + + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); +} + +/* ---------------------------------------------------------------------- + reset local array ptrs +------------------------------------------------------------------------- */ + +void AtomVec::grow_reset() +{ + // NOTE: is this method needed anymore + tag = atom->tag; type = atom->type; + mask = atom->mask; image = atom->image; + x = atom->x; v = atom->v; f = atom->f; +} + +/* ---------------------------------------------------------------------- + copy atom I info to atom J +------------------------------------------------------------------------- */ + +void AtomVec::copy(int i, int j, int delflag) +{ + int m,n,datatype,cols,collength,ncols; + void *pdata,*plength; + + tag[j] = tag[i]; + type[j] = type[i]; + mask[j] = mask[i]; + image[j] = image[i]; + x[j][0] = x[i][0]; + x[j][1] = x[i][1]; + x[j][2] = x[i][2]; + v[j][0] = v[i][0]; + v[j][1] = v[i][1]; + v[j][2] = v[i][2]; + + if (ncopy) { + for (n = 0; n < ncopy; n++) { + pdata = mcopy.pdata[n]; + datatype = mcopy.datatype[n]; + cols = mcopy.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[j] = vec[i]; + } else if (cols > 0) { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + array[j][m] = array[i][m]; + } else { + double **array = *((double ***) pdata); + collength = mcopy.collength[n]; + plength = mcopy.plength[n]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (m = 0; m < ncols; m++) + array[j][m] = array[i][m]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[j] = vec[i]; + } else if (cols > 0) { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + array[j][m] = array[i][m]; + } else { + int **array = *((int ***) pdata); + collength = mcopy.collength[n]; + plength = mcopy.plength[n]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (m = 0; m < ncols; m++) + array[j][m] = array[i][m]; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[j] = vec[i]; + } else if (cols > 0) { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + array[j][m] = array[i][m]; + } else { + bigint **array = *((bigint ***) pdata); + collength = mcopy.collength[n]; + plength = mcopy.plength[n]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (m = 0; m < ncols; m++) + array[j][m] = array[i][m]; + } + } + } + } + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); +} + +/* ---------------------------------------------------------------------- */ + +int AtomVec::pack_comm(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m,mm,nn,datatype,cols; + double dx,dy,dz; + void *pdata; + + m = 0; + if (pbc_flag == 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]; + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; + dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; + dz = pbc[2]*domain->zprd; + } + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + } + } + + if (comm) { + for (nn = 0; nn < ncomm; nn++) { + pdata = mcomm.pdata[nn]; + datatype = mcomm.datatype[nn]; + cols = mcomm.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = vec[j]; + } + } else { + double **array = *((double ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = array[j][mm]; + } + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + int **array = *((int ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + bigint **array = *((bigint ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } + } + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVec::pack_comm_vel(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m,mm,nn,datatype,cols; + double dx,dy,dz,dvx,dvy,dvz; + void *pdata; + + m = 0; + if (pbc_flag == 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]; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; + dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; + dz = pbc[2]*domain->zprd; + } + if (!deform_vremap) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; + dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; + dvz = pbc[2]*h_rate[2]; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + if (mask[i] & deform_groupbit) { + buf[m++] = v[j][0] + dvx; + buf[m++] = v[j][1] + dvy; + buf[m++] = v[j][2] + dvz; + } else { + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } + } + } + + if (ncomm_vel) { + for (nn = 0; nn < ncomm_vel; nn++) { + pdata = mcomm_vel.pdata[nn]; + datatype = mcomm_vel.datatype[nn]; + cols = mcomm_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = vec[j]; + } + } else { + double **array = *((double ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = array[j][mm]; + } + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + int **array = *((int ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + bigint **array = *((bigint ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } + } + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVec::unpack_comm(int n, int first, double *buf) +{ + int i,m,last,mm,nn,datatype,cols; + void *pdata; + + 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++]; + } + + if (ncomm) { + for (nn = 0; nn < ncomm; nn++) { + pdata = mcomm.pdata[nn]; + datatype = mcomm.datatype[nn]; + cols = mcomm.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = first; i < last; i++) + vec[i] = buf[m++]; + } else { + double **array = *((double ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = buf[m++]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = first; i < last; i++) + vec[i] = ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (int) ubuf(buf[m++]).i; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = first; i < last; i++) + vec[i] = (bigint) ubuf(buf[m++]).i; + } else { + bigint **array = *((bigint ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (bigint) ubuf(buf[m++]).i; + } + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +void AtomVec::unpack_comm_vel(int n, int first, double *buf) +{ + int i,m,last,mm,nn,datatype,cols; + void *pdata; + + 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++]; + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; + } + + if (ncomm_vel) { + for (nn = 0; nn < ncomm_vel; nn++) { + pdata = mcomm_vel.pdata[nn]; + datatype = mcomm_vel.datatype[nn]; + cols = mcomm_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = first; i < last; i++) + vec[i] = buf[m++]; + } else { + double **array = *((double ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = buf[m++]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = first; i < last; i++) + vec[i] = ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (int) ubuf(buf[m++]).i; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = first; i < last; i++) + vec[i] = (bigint) ubuf(buf[m++]).i; + } else { + bigint **array = *((bigint ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (bigint) ubuf(buf[m++]).i; + } + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +int AtomVec::pack_reverse(int n, int first, double *buf) +{ + int i,m,last,mm,nn,datatype,cols; + void *pdata; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + buf[m++] = f[i][0]; + buf[m++] = f[i][1]; + buf[m++] = f[i][2]; + } + + if (nreverse) { + for (nn = 0; nn < nreverse; nn++) { + pdata = mreverse.pdata[nn]; + datatype = mreverse.datatype[nn]; + cols = mreverse.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = first; i < last; i++) { + buf[m++] = vec[i]; + } + } else { + double **array = *((double ***) pdata); + for (i = first; i < last; i++) { + for (mm = 0; mm < cols; mm++) + buf[m++] = array[i][mm]; + } + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = first; i < last; i++) { + buf[m++] = ubuf(vec[i]).d; + } + } else { + int **array = *((int ***) pdata); + for (i = first; i < last; i++) { + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = first; i < last; i++) { + buf[m++] = ubuf(vec[i]).d; + } + } else { + bigint **array = *((bigint ***) pdata); + for (i = first; i < last; i++) { + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } + } + } + } + } + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVec::unpack_reverse(int n, int *list, double *buf) +{ + int i,j,m,mm,nn,datatype,cols; + void *pdata; + + m = 0; + for (i = 0; i < n; i++) { + j = list[i]; + f[j][0] += buf[m++]; + f[j][1] += buf[m++]; + f[j][2] += buf[m++]; + } + + if (nreverse) { + for (nn = 0; nn < nreverse; nn++) { + pdata = mreverse.pdata[nn]; + datatype = mreverse.datatype[nn]; + cols = mreverse.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + vec[j] += buf[m++]; + } + } else { + double **array = *((double ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + array[j][mm] += buf[m++]; + } + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + vec[j] += buf[m++]; + } + } else { + int **array = *((int ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + array[j][mm] += buf[m++]; + } + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + vec[j] += buf[m++]; + } + } else { + bigint **array = *((bigint ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + array[j][mm] += buf[m++]; + } + } + } + } + } +} + +/* ---------------------------------------------------------------------- */ + +int AtomVec::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) +{ + int i,j,m,mm,nn,datatype,cols; + double dx,dy,dz; + void *pdata; + + m = 0; + if (pbc_flag == 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]; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]; + dy = pbc[1]; + dz = pbc[2]; + } + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + } + } + + if (nborder) { + for (nn = 0; nn < nborder; nn++) { + pdata = mborder.pdata[nn]; + datatype = mborder.datatype[nn]; + cols = mborder.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = vec[j]; + } + } else { + double **array = *((double ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = array[j][mm]; + } + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + int **array = *((int ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + bigint **array = *((bigint ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); + + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVec::pack_border_vel(int n, int *list, double *buf, + int pbc_flag, int *pbc) +{ + int i,j,m,mm,nn,datatype,cols; + double dx,dy,dz,dvx,dvy,dvz; + void *pdata; + + m = 0; + if (pbc_flag == 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]; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + if (domain->triclinic == 0) { + dx = pbc[0]*domain->xprd; + dy = pbc[1]*domain->yprd; + dz = pbc[2]*domain->zprd; + } else { + dx = pbc[0]; + dy = pbc[1]; + dz = pbc[2]; + } + if (!deform_vremap) { + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } else { + dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; + dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; + dvz = pbc[2]*h_rate[2]; + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = x[j][0] + dx; + buf[m++] = x[j][1] + dy; + buf[m++] = x[j][2] + dz; + buf[m++] = ubuf(tag[j]).d; + buf[m++] = ubuf(type[j]).d; + buf[m++] = ubuf(mask[j]).d; + if (mask[i] & deform_groupbit) { + buf[m++] = v[j][0] + dvx; + buf[m++] = v[j][1] + dvy; + buf[m++] = v[j][2] + dvz; + } else { + buf[m++] = v[j][0]; + buf[m++] = v[j][1]; + buf[m++] = v[j][2]; + } + } + } + } + + if (nborder_vel) { + for (nn = 0; nn < nborder_vel; nn++) { + pdata = mborder_vel.pdata[nn]; + datatype = mborder_vel.datatype[nn]; + cols = mborder_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = vec[j]; + } + } else { + double **array = *((double ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = array[j][mm]; + } + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + int **array = *((int ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + buf[m++] = ubuf(vec[j]).d; + } + } else { + bigint **array = *((bigint ***) pdata); + for (i = 0; i < n; i++) { + j = list[i]; + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[j][mm]).d; + } + } + } + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); + + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVec::unpack_border(int n, int first, double *buf) +{ + int i,m,last,mm,nn,datatype,cols; + void *pdata; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (i == nmax) grow(0); + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + tag[i] = (tagint) ubuf(buf[m++]).i; + type[i] = (int) ubuf(buf[m++]).i; + mask[i] = (int) ubuf(buf[m++]).i; + } + + if (nborder) { + for (nn = 0; nn < nborder; nn++) { + pdata = mborder.pdata[nn]; + datatype = mborder.datatype[nn]; + cols = mborder.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = first; i < last; i++) + vec[i] = buf[m++]; + } else { + double **array = *((double ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = buf[m++]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = first; i < last; i++) + vec[i] = ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (int) ubuf(buf[m++]).i; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = first; i < last; i++) + vec[i] = (bigint) ubuf(buf[m++]).i; + } else { + bigint **array = *((bigint ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (bigint) ubuf(buf[m++]).i; + } + } + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]-> + unpack_border(n,first,&buf[m]); +} + +/* ---------------------------------------------------------------------- */ + +void AtomVec::unpack_border_vel(int n, int first, double *buf) +{ + int i,m,last,mm,nn,datatype,cols; + void *pdata; + + m = 0; + last = first + n; + for (i = first; i < last; i++) { + if (i == nmax) grow(0); + x[i][0] = buf[m++]; + x[i][1] = buf[m++]; + x[i][2] = buf[m++]; + tag[i] = (tagint) ubuf(buf[m++]).i; + type[i] = (int) ubuf(buf[m++]).i; + mask[i] = (int) ubuf(buf[m++]).i; + v[i][0] = buf[m++]; + v[i][1] = buf[m++]; + v[i][2] = buf[m++]; + } + + if (nborder_vel) { + for (nn = 0; nn < nborder_vel; nn++) { + pdata = mborder_vel.pdata[nn]; + datatype = mborder_vel.datatype[nn]; + cols = mborder_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + for (i = first; i < last; i++) + vec[i] = buf[m++]; + } else { + double **array = *((double ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = buf[m++]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + for (i = first; i < last; i++) + vec[i] = ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (int) ubuf(buf[m++]).i; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + for (i = first; i < last; i++) + vec[i] = (bigint) ubuf(buf[m++]).i; + } else { + bigint **array = *((bigint ***) pdata); + for (i = first; i < last; i++) + for (mm = 0; mm < cols; mm++) + array[i][mm] = (bigint) ubuf(buf[m++]).i; + } + } + } + } + + if (atom->nextra_border) + for (int iextra = 0; iextra < atom->nextra_border; iextra++) + m += modify->fix[atom->extra_border[iextra]]-> + unpack_border(n,first,&buf[m]); +} + +/* ---------------------------------------------------------------------- + pack data for atom I for sending to another proc + xyz must be 1st 3 values, so comm::exchange() can test on them +------------------------------------------------------------------------- */ + +int AtomVec::pack_exchange(int i, double *buf) +{ + int mm,nn,datatype,cols,collength,ncols; + void *pdata,*plength; + + int m = 1; + buf[m++] = x[i][0]; + buf[m++] = x[i][1]; + buf[m++] = x[i][2]; + buf[m++] = v[i][0]; + buf[m++] = v[i][1]; + buf[m++] = v[i][2]; + buf[m++] = ubuf(tag[i]).d; + buf[m++] = ubuf(type[i]).d; + buf[m++] = ubuf(mask[i]).d; + buf[m++] = ubuf(image[i]).d; + + if (nexchange) { + for (nn = 0; nn < nexchange; nn++) { + pdata = mexchange.pdata[nn]; + datatype = mexchange.datatype[nn]; + cols = mexchange.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + buf[m++] = vec[i]; + } else if (cols > 0) { + double **array = *((double ***) pdata); + for (mm = 0; mm < cols; mm++) + buf[m++] = array[i][mm]; + } else { + double **array = *((double ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (mm = 0; mm < ncols; mm++) + buf[m++] = array[i][mm]; + } + } if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + buf[m++] = ubuf(vec[i]).d; + } else if (cols > 0) { + int **array = *((int ***) pdata); + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } else { + int **array = *((int ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (mm = 0; mm < ncols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } + } if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + buf[m++] = ubuf(vec[i]).d; + } else if (cols > 0) { + bigint **array = *((bigint ***) pdata); + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } else { + bigint **array = *((bigint ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (mm = 0; mm < ncols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } + } + } + } + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); + + buf[0] = m; + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVec::unpack_exchange(double *buf) +{ + int mm,nn,datatype,cols,collength,ncols; + void *pdata,*plength; + + int nlocal = atom->nlocal; + if (nlocal == nmax) grow(0); + + int m = 1; + x[nlocal][0] = buf[m++]; + x[nlocal][1] = buf[m++]; + x[nlocal][2] = buf[m++]; + v[nlocal][0] = buf[m++]; + v[nlocal][1] = buf[m++]; + v[nlocal][2] = buf[m++]; + tag[nlocal] = (tagint) ubuf(buf[m++]).i; + type[nlocal] = (int) ubuf(buf[m++]).i; + mask[nlocal] = (int) ubuf(buf[m++]).i; + image[nlocal] = (imageint) ubuf(buf[m++]).i; + + if (nexchange) { + for (nn = 0; nn < nexchange; nn++) { + pdata = mexchange.pdata[nn]; + datatype = mexchange.datatype[nn]; + cols = mexchange.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[nlocal] = buf[m++]; + } else if (cols > 0) { + double **array = *((double ***) pdata); + for (mm = 0; mm < cols; mm++) + array[nlocal][mm] = buf[m++]; + } else { + double **array = *((double ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + for (mm = 0; mm < ncols; mm++) + array[nlocal][mm] = buf[m++]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[nlocal] = ubuf(buf[m++]).i; + } else if (cols > 0) { + int **array = *((int ***) pdata); + for (mm = 0; mm < cols; mm++) + array[nlocal][mm] = (int) ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + for (mm = 0; mm < ncols; mm++) + array[nlocal][mm] = (int) ubuf(buf[m++]).i; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[nlocal] = (bigint) ubuf(buf[m++]).i; + } else if (cols > 0) { + bigint **array = *((bigint ***) pdata); + for (mm = 0; mm < cols; mm++) + array[nlocal][mm] = (bigint) ubuf(buf[m++]).i; + } else { + bigint **array = *((bigint ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + for (mm = 0; mm < ncols; mm++) + array[nlocal][mm] = (bigint) ubuf(buf[m++]).i; + } + } + } + } + + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + m += modify->fix[atom->extra_grow[iextra]]-> + unpack_exchange(nlocal,&buf[m]); + + atom->nlocal++; + return m; +} + +/* ---------------------------------------------------------------------- + size of restart data for all atoms owned by this proc + include extra data stored by fixes +------------------------------------------------------------------------- */ + +int AtomVec::size_restart() +{ + int i,nn,cols,collength,ncols; + void *plength; + + // NOTE: need to worry about overflow of returned int ?? + + int nlocal = atom->nlocal; + + // 11 = length storage + id,type,mask,image,x,v + + int n = 11 * nlocal; + + if (nrestart) { + for (nn = 0; nn < nrestart; nn++) { + cols = mrestart.cols[i]; + if (cols == 0) n += nlocal; + else if (cols > 0) n += cols*nlocal; + else { + collength = mrestart.collength[nn]; + plength = mrestart.plength[nn]; + for (i = 0; i < nlocal; i++) { + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + n += ncols; + } + } + } + } + + if (atom->nextra_restart) + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) + for (i = 0; i < nlocal; i++) + n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + + return n; +} + +/* ---------------------------------------------------------------------- + pack atom I's data for restart file including extra quantities + xyz must be 1st 3 values, so that read_restart can test on them + molecular types may be negative, but write as positive +------------------------------------------------------------------------- */ + +int AtomVec::pack_restart(int i, double *buf) +{ + int mm,nn,datatype,cols,collength,ncols; + void *pdata,*plength; + + int m = 1; + buf[m++] = x[i][0]; + buf[m++] = x[i][1]; + buf[m++] = x[i][2]; + buf[m++] = ubuf(tag[i]).d; + buf[m++] = ubuf(type[i]).d; + buf[m++] = ubuf(mask[i]).d; + buf[m++] = ubuf(image[i]).d; + buf[m++] = v[i][0]; + buf[m++] = v[i][1]; + buf[m++] = v[i][2]; + + for (nn = 0; nn < nrestart; nn++) { + pdata = mrestart.pdata[nn]; + datatype = mrestart.datatype[nn]; + cols = mrestart.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + buf[m++] = vec[i]; + } else if (ncols > 0) { + double **array = *((double ***) pdata); + for (mm = 0; mm < cols; mm++) + buf[m++] = array[i][mm]; + } else { + double **array = *((double ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (mm = 0; mm < ncols; mm++) + buf[m++] = array[i][mm]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + buf[m++] = ubuf(vec[i]).d; + } else if (cols > 0) { + int **array = *((int ***) pdata); + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } else { + int **array = *((int ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (mm = 0; mm < ncols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + buf[m++] = ubuf(vec[i]).d; + } else if (ncols > 0) { + bigint **array = *((bigint ***) pdata); + for (mm = 0; mm < cols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } else { + bigint **array = *((bigint ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; + for (mm = 0; mm < ncols; mm++) + buf[m++] = ubuf(array[i][mm]).d; + } + } + } + + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) + m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); + + buf[0] = m; + return m; +} + +/* ---------------------------------------------------------------------- + unpack data for one atom from restart file including extra quantities +------------------------------------------------------------------------- */ + +int AtomVec::unpack_restart(double *buf) +{ + int mm,nn,datatype,cols,collength,ncols; + void *pdata,*plength; + + int nlocal = atom->nlocal; + if (nlocal == nmax) { + grow(0); + if (atom->nextra_store) + memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); + } + + int m = 1; + x[nlocal][0] = buf[m++]; + x[nlocal][1] = buf[m++]; + x[nlocal][2] = buf[m++]; + tag[nlocal] = (tagint) ubuf(buf[m++]).i; + type[nlocal] = (int) ubuf(buf[m++]).i; + mask[nlocal] = (int) ubuf(buf[m++]).i; + image[nlocal] = (imageint) ubuf(buf[m++]).i; + v[nlocal][0] = buf[m++]; + v[nlocal][1] = buf[m++]; + v[nlocal][2] = buf[m++]; + + for (nn = 0; nn < nrestart; nn++) { + pdata = mrestart.pdata[nn]; + datatype = mrestart.datatype[nn]; + cols = mrestart.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[nlocal] = buf[m++]; + } else if (cols > 0) { + double **array = *((double ***) pdata); + for (mm = 0; mm < cols; mm++) + array[nlocal][mm] = buf[m++]; + } else { + double **array = *((double ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + for (mm = 0; mm < ncols; mm++) + array[nlocal][mm] = buf[m++]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[nlocal] = ubuf(buf[m++]).i; + } else if (cols > 0) { + int **array = *((int ***) pdata); + for (mm = 0; mm < cols; mm++) + array[nlocal][mm] = (int) ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + for (mm = 0; mm < ncols; mm++) + array[nlocal][mm] = (int) ubuf(buf[m++]).i; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[nlocal] = (bigint) ubuf(buf[m++]).i; + } else if (cols > 0) { + bigint **array = *((bigint ***) pdata); + for (mm = 0; mm < cols; mm++) + array[nlocal][mm] = (bigint) ubuf(buf[m++]).i; + } else { + int **array = *((int ***) pdata); + collength = mexchange.collength[nn]; + plength = mexchange.plength[nn]; + if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; + else ncols = (*((int **) plength))[nlocal]; + for (mm = 0; mm < ncols; mm++) + array[nlocal][mm] = (bigint) ubuf(buf[m++]).i; + } + } + } + + double **extra = atom->extra; + if (atom->nextra_store) { + int size = static_cast (buf[0]) - m; + for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; + } + + atom->nlocal++; + return m; +} + +/* ---------------------------------------------------------------------- + create one atom of itype at coord + set other values to defaults +------------------------------------------------------------------------- */ + +void AtomVec::create_atom(int itype, double *coord) +{ + int m,n,datatype,cols; + void *pdata; + + int nlocal = atom->nlocal; + if (nlocal == nmax) grow(0); + + tag[nlocal] = 0; + type[nlocal] = itype; + x[nlocal][0] = coord[0]; + x[nlocal][1] = coord[1]; + x[nlocal][2] = coord[2]; + mask[nlocal] = 1; + image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | + ((imageint) IMGMAX << IMGBITS) | IMGMAX; + v[nlocal][0] = 0.0; + v[nlocal][1] = 0.0; + v[nlocal][2] = 0.0; + + // special-case initialization for some fields + + for (n = 0; n < ncreate; n++) { + pdata = mcreate.pdata[n]; + datatype = mcreate.datatype[n]; + cols = mcreate.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[nlocal] = 0.0; + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + array[nlocal][m] = 0.0; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[nlocal] = 0; + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + array[nlocal][m] = 0; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[nlocal] = 0; + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + array[nlocal][m] = 0; + } + } + } + + atom->nlocal++; +} + +/* ---------------------------------------------------------------------- + unpack one line from Atoms section of data file + initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) +{ + int m,n,datatype,cols; + void *pdata; + + int nlocal = atom->nlocal; + if (nlocal == nmax) grow(0); + + x[nlocal][0] = coord[0]; + x[nlocal][1] = coord[1]; + x[nlocal][2] = coord[2]; + mask[nlocal] = 1; + image[nlocal] = imagetmp; + v[nlocal][0] = 0.0; + v[nlocal][1] = 0.0; + v[nlocal][2] = 0.0; + + int ivalue = 0; + for (n = 0; n < ndata_atom; n++) { + pdata = mdata_atom.pdata[n]; + datatype = mdata_atom.datatype[n]; + cols = mdata_atom.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[nlocal] = utils::numeric(FLERR,values[ivalue++],true,lmp); + } else { + double **array = *((double ***) pdata); + if (array == atom->x) { // already set by coord arg + ivalue += cols; + continue; + } + for (m = 0; m < cols; m++) + array[nlocal][m] = utils::numeric(FLERR,values[ivalue++],true,lmp); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[nlocal] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + array[nlocal][m] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[nlocal] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + array[nlocal][m] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + } + } + } + + // error checks applicable to all styles + + if (atom->tag[nlocal] <= 0) + error->one(FLERR,"Invalid atom ID in Atoms section of data file"); + if (atom->type[nlocal] <= 0 || atom->type[nlocal] > atom->ntypes) + error->one(FLERR,"Invalid atom type in Atoms section of data file"); + + atom->nlocal++; +} + +/* ---------------------------------------------------------------------- + pack atom info for data file including 3 image flags +------------------------------------------------------------------------- */ + +void AtomVec::pack_data(double **buf) +{ + int i,j,m,n,datatype,cols; + void *pdata; + + int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) { + j = 0; + for (n = 0; n < ndata_atom; n++) { + pdata = mdata_atom.pdata[n]; + datatype = mdata_atom.datatype[n]; + cols = mdata_atom.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + buf[i][j++] = vec[i]; + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = array[i][m]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + buf[i][j++] = ubuf(vec[i]).d; + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = ubuf(array[i][m]).d; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + buf[i][j++] = ubuf(vec[i]).d; + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = ubuf(array[i][m]).d; + } + } + } + + buf[i][j++] = ubuf((image[i] & IMGMASK) - IMGMAX).d; + buf[i][j++] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; + buf[i][j++] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; + } +} + +/* ---------------------------------------------------------------------- + write atom info to data file + id is first field, 3 image flags are final fields +------------------------------------------------------------------------- */ + +void AtomVec::write_data(FILE *fp, int n, double **buf) +{ + int i,j,m,nn,datatype,cols; + void *pdata; + + for (i = 0; i < n; i++) { + fprintf(fp,TAGINT_FORMAT,(tagint) ubuf(buf[i][0]).i); + + j = 1; + for (nn = 1; nn < ndata_atom; nn++) { + pdata = mdata_atom.pdata[nn]; + datatype = mdata_atom.datatype[nn]; + cols = mdata_atom.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + fprintf(fp," %-1.16e",buf[i][j++]); + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," %-1.16e",buf[i][j++]); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } + } + } + + fprintf(fp," %d %d %d\n", + (int) ubuf(buf[i][j]).i, + (int) ubuf(buf[i][j+1]).i, + (int) ubuf(buf[i][j+2]).i); + } +} + /* ---------------------------------------------------------------------- unpack one line from Velocities section of data file ------------------------------------------------------------------------- */ -void AtomVec::data_vel(int m, char **values) +void AtomVec::data_vel(int ilocal, char **values) { + int m,n,datatype,cols; + void *pdata; + double **v = atom->v; - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); + v[ilocal][0] = utils::numeric(FLERR,values[0],true,lmp); + v[ilocal][1] = utils::numeric(FLERR,values[1],true,lmp); + v[ilocal][2] = utils::numeric(FLERR,values[2],true,lmp); + + int ivalue = 3; + for (n = 0; n < ndata_vel; n++) { + pdata = mdata_vel.pdata[n]; + datatype = mdata_vel.datatype[n]; + cols = mdata_vel.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[ilocal] = utils::numeric(FLERR,values[ivalue++],true,lmp); + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + array[ilocal][m] = utils::numeric(FLERR,values[ivalue++],true,lmp); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[ilocal] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + array[ilocal][m] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[ilocal] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + array[ilocal][m] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + } + } + } } /* ---------------------------------------------------------------------- @@ -126,27 +2085,109 @@ void AtomVec::data_vel(int m, char **values) void AtomVec::pack_vel(double **buf) { + int i,j,m,n,datatype,cols; + void *pdata; + double **v = atom->v; tagint *tag = atom->tag; int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { + for (i = 0; i < nlocal; i++) { buf[i][0] = ubuf(tag[i]).d; buf[i][1] = v[i][0]; buf[i][2] = v[i][1]; buf[i][3] = v[i][2]; + + j = 4; + if (ndata_vel) { + for (n = 0; n < ndata_vel; n++) { + pdata = mdata_vel.pdata[n]; + datatype = mdata_vel.datatype[n]; + cols = mdata_vel.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + buf[i][j++] = vec[i]; + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = array[i][m]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + buf[i][j++] = ubuf(vec[i]).d; + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = ubuf(array[i][m]).d; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + buf[i][j++] = ubuf(vec[i]).d; + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = ubuf(array[i][m]).d; + } + } + } + } } } /* ---------------------------------------------------------------------- write velocity info to data file + id and velocity vector are first 4 fields ------------------------------------------------------------------------- */ void AtomVec::write_vel(FILE *fp, int n, double **buf) { - for (int i = 0; i < n; i++) + int i,j,m,nn,datatype,cols; + void *pdata; + + for (i = 0; i < n; i++) { fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e\n", (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]); + + j = 4; + for (nn = 0; nn < ndata_vel; nn++) { + pdata = mdata_vel.pdata[nn]; + datatype = mdata_vel.datatype[nn]; + cols = mdata_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + fprintf(fp," %-1.16e",buf[i][j++]); + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," %-1.16e",buf[i][j++]); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } + } + } + + fprintf(fp,"\n"); + } } /* ---------------------------------------------------------------------- @@ -395,3 +2436,60 @@ void AtomVec::write_improper(FILE *fp, int n, tagint **buf, int index) index++; } } + +/* ---------------------------------------------------------------------- + return # of bytes of allocated memory +------------------------------------------------------------------------- */ + +bigint AtomVec::memory_usage() +{ + int datatype,cols,index,maxcols; + void *pdata; + + bigint bytes = 0; + + bytes += memory->usage(tag,nmax); + bytes += memory->usage(type,nmax); + bytes += memory->usage(mask,nmax); + bytes += memory->usage(image,nmax); + bytes += memory->usage(x,nmax,3); + bytes += memory->usage(v,nmax,3); + bytes += memory->usage(f,nmax*nthreads,3); + + for (int i = 0; i < ngrow; i++) { + pdata = mgrow.pdata[i]; + datatype = mgrow.datatype[i]; + cols = mgrow.cols[i]; + index = mgrow.index[i]; + if (datatype == DOUBLE) { + if (cols == 0) { + bytes += memory->usage(*((double **) pdata),nmax*threads[i]); + } else if (cols > 0) { + bytes += memory->usage(*((double ***) pdata),nmax*threads[i],cols); + } else { + maxcols = *(mgrow.maxcols[i]); + bytes += memory->usage(*((double ***) pdata),nmax*threads[i],maxcols); + } + } else if (datatype == INT) { + if (cols == 0) { + bytes += memory->usage(*((int **) pdata),nmax*threads[i]); + } else if (cols > 0) { + bytes += memory->usage(*((int ***) pdata),nmax*threads[i],cols); + } else { + maxcols = *(mgrow.maxcols[i]); + bytes += memory->usage(*((int ***) pdata),nmax*threads[i],maxcols); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bytes += memory->usage(*((bigint **) pdata),nmax*threads[i]); + } else if (cols > 0) { + bytes += memory->usage(*((bigint ***) pdata),nmax*threads[i],cols); + } else { + maxcols = *(mgrow.maxcols[i]); + bytes += memory->usage(*((bigint ***) pdata),nmax*threads[i],maxcols); + } + } + } + + return bytes; +} diff --git a/src/atom_vec.h b/src/atom_vec.h index 2b57238c3b..c3551b541d 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -55,54 +55,54 @@ class AtomVec : protected Pointers { virtual void process_args(int, char **); virtual void init(); - virtual void grow(int) = 0; - virtual void grow_reset() = 0; - virtual void copy(int, int, int) = 0; - virtual void clear_bonus() {} - virtual void force_clear(int, size_t) {} - - virtual int pack_comm(int, int *, double *, int, int *) = 0; - virtual int pack_comm_vel(int, int *, double *, int, int *) = 0; - virtual int pack_comm_hybrid(int, int *, double *) {return 0;} - virtual void unpack_comm(int, int, double *) = 0; - virtual void unpack_comm_vel(int, int, double *) = 0; - virtual int unpack_comm_hybrid(int, int, double *) {return 0;} - - virtual int pack_reverse(int, int, double *) = 0; - virtual int pack_reverse_hybrid(int, int, double *) {return 0;} - virtual void unpack_reverse(int, int *, double *) = 0; - virtual int unpack_reverse_hybrid(int, int *, double *) {return 0;} - - virtual int pack_border(int, int *, double *, int, int *) = 0; - virtual int pack_border_vel(int, int *, double *, int, int *) = 0; - virtual int pack_border_hybrid(int, int *, double *) {return 0;} - virtual void unpack_border(int, int, double *) = 0; - virtual void unpack_border_vel(int, int, double *) = 0; - virtual int unpack_border_hybrid(int, int, double *) {return 0;} - - virtual int pack_exchange(int, double *) = 0; - virtual int unpack_exchange(double *) = 0; - - virtual int size_restart() = 0; - virtual int pack_restart(int, double *) = 0; - virtual int unpack_restart(double *) = 0; - - virtual void create_atom(int, double *) = 0; - - virtual void data_atom(double *, imageint, char **) = 0; - virtual void data_atom_bonus(int, char **) {} - virtual int data_atom_hybrid(int, char **) {return 0;} - virtual void data_vel(int, char **); - virtual int data_vel_hybrid(int, char **) {return 0;} - - virtual void pack_data(double **) = 0; - virtual int pack_data_hybrid(int, double *) {return 0;} - virtual void write_data(FILE *, int, double **) = 0; - virtual int write_data_hybrid(FILE *, double *) {return 0;} - virtual void pack_vel(double **); - virtual int pack_vel_hybrid(int, double *) {return 0;} - virtual void write_vel(FILE *, int, double **); - virtual int write_vel_hybrid(FILE *, double *) {return 0;} + void grow(int); + void grow_reset(); + void copy(int, int, int); + void clear_bonus() {} + void force_clear(int, size_t) {} + + int pack_comm(int, int *, double *, int, int *); + int pack_comm_vel(int, int *, double *, int, int *); + int pack_comm_hybrid(int, int *, double *) {return 0;} + void unpack_comm(int, int, double *); + void unpack_comm_vel(int, int, double *); + int unpack_comm_hybrid(int, int, double *) {return 0;} + + int pack_reverse(int, int, double *); + int pack_reverse_hybrid(int, int, double *) {return 0;} + void unpack_reverse(int, int *, double *); + int unpack_reverse_hybrid(int, int *, double *) {return 0;} + + int pack_border(int, int *, double *, int, int *); + int pack_border_vel(int, int *, double *, int, int *); + int pack_border_hybrid(int, int *, double *) {return 0;} + void unpack_border(int, int, double *); + void unpack_border_vel(int, int, double *); + int unpack_border_hybrid(int, int, double *) {return 0;} + + int pack_exchange(int, double *); + int unpack_exchange(double *); + + int size_restart(); + virtual int pack_restart(int, double *); + virtual int unpack_restart(double *); + + virtual void create_atom(int, double *); + + virtual void data_atom(double *, imageint, char **); + void data_atom_bonus(int, char **) {} + int data_atom_hybrid(int, char **) {return 0;} + void data_vel(int, char **); + int data_vel_hybrid(int, char **) {return 0;} + + void pack_data(double **); + int pack_data_hybrid(int, double *) {return 0;} + void write_data(FILE *, int, double **); + int write_data_hybrid(FILE *, double *) {return 0;} + void pack_vel(double **); + int pack_vel_hybrid(int, double *) {return 0;} + void write_vel(FILE *, int, double **); + int write_vel_hybrid(FILE *, double *) {return 0;} int pack_bond(tagint **); void write_bond(FILE *, int, tagint **, int); @@ -113,10 +113,10 @@ class AtomVec : protected Pointers { int pack_improper(tagint **); void write_improper(FILE *, int, tagint **, int); - virtual int property_atom(char *) {return -1;} - virtual void pack_property_atom(int, double *, int, int) {} + int property_atom(char *) {return -1;} + void pack_property_atom(int, double *, int, int) {} - virtual bigint memory_usage() = 0; + bigint memory_usage(); protected: int nmax; // local copy of atom->nmax @@ -124,6 +124,47 @@ class AtomVec : protected Pointers { int deform_groupbit; double *h_rate; + tagint *tag; // peratom fields common to all styles + int *type,*mask; + imageint *image; + double **x,**v,**f; + + const char *default_grow,*default_copy; + const char *default_comm,*default_comm_vel,*default_reverse; + const char *default_border,*default_border_vel; + const char *default_exchange,*default_restart; + const char *default_create,*default_data_atom,*default_data_vel; + + char *fields_grow,*fields_copy; + char *fields_comm,*fields_comm_vel,*fields_reverse; + char *fields_border,*fields_border_vel; + char *fields_exchange,*fields_restart; + char *fields_create,*fields_data_atom,*fields_data_vel; + + struct Method { + void **pdata; + int *datatype; + int *cols; + int **maxcols; + int *collength; + void **plength; + int *index; + }; + + Method mgrow,mcopy; + Method mcomm,mcomm_vel,mreverse,mborder,mborder_vel,mexchange,mrestart; + Method mcreate,mdata_atom,mdata_vel; + + int ngrow,ncopy; + int ncomm,ncomm_vel,nreverse,nborder,nborder_vel,nexchange,nrestart; + int ncreate,ndata_atom,ndata_vel; + + // thread info for fields that are duplicated over threads + // used by fields in grow() and memory_usage() + + int nthreads; + int *threads; + // union data struct for packing 32-bit and 64-bit ints into double bufs // this avoids aliasing issues by having 2 pointers (double,int) // to same buf memory @@ -143,8 +184,15 @@ class AtomVec : protected Pointers { ubuf(int arg) : i(arg) {} }; + // local methods + void grow_nmax(); int grow_nmax_bonus(int); + void setup_fields(); + int process_fields(char *, const char *, Method *); + void create_method(int, Method *); + void init_method(Method *); + void destroy_method(Method *); }; } @@ -161,4 +209,13 @@ E: KOKKOS package requires a kokkos enabled atom_style Self-explanatory. +E: Per-processor system is too big + +The number of owned atoms plus ghost atoms on a single +processor must fit in 32-bit integer. + +E: Invalid atom type in Atoms section of data file + +Atom types must range from 1 to specified # of types. + */ diff --git a/src/atom_vec_atomic.cpp b/src/atom_vec_atomic.cpp index 25a28f1668..a283e99081 100644 --- a/src/atom_vec_atomic.cpp +++ b/src/atom_vec_atomic.cpp @@ -12,14 +12,6 @@ ------------------------------------------------------------------------- */ #include "atom_vec_atomic.h" -#include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" -#include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -30,654 +22,23 @@ AtomVecAtomic::AtomVecAtomic(LAMMPS *lmp) : AtomVec(lmp) molecular = 0; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 6; - size_velocity = 3; - size_data_atom = 5; - size_data_vel = 4; - xcol_data = 3; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecAtomic::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecAtomic::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecAtomic::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAtomic::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAtomic::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAtomic::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAtomic::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecAtomic::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecAtomic::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecAtomic::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 11 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecAtomic::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecAtomic::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecAtomic::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecAtomic::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecAtomic::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = x[i][0]; - buf[i][3] = x[i][1]; - buf[i][4] = x[i][2]; - buf[i][5] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][6] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecAtomic::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4], - (int) ubuf(buf[i][5]).i,(int) ubuf(buf[i][6]).i, - (int) ubuf(buf[i][7]).i); -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecAtomic::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - return bytes; + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = NULL; + fields_copy = NULL; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = NULL; + fields_border_vel = NULL; + fields_exchange = NULL; + fields_restart = NULL; + fields_create = NULL; + fields_data_atom = (char *) "id type x"; + fields_data_vel = NULL; + + setup_fields(); } diff --git a/src/atom_vec_atomic.h b/src/atom_vec_atomic.h index afcede89b1..3caf1a5a94 100644 --- a/src/atom_vec_atomic.h +++ b/src/atom_vec_atomic.h @@ -27,36 +27,7 @@ namespace LAMMPS_NS { class AtomVecAtomic : public AtomVec { public: AtomVecAtomic(class LAMMPS *); - virtual ~AtomVecAtomic() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - void pack_data(double **); - void write_data(FILE *, int, double **); - bigint memory_usage(); - - protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; + ~AtomVecAtomic() {} }; } @@ -66,13 +37,4 @@ class AtomVecAtomic : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/atom_vec_charge.cpp b/src/atom_vec_charge.cpp index 9f35d16ff0..9c8f18a846 100644 --- a/src/atom_vec_charge.cpp +++ b/src/atom_vec_charge.cpp @@ -13,13 +13,6 @@ #include "atom_vec_charge.h" #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" -#include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -30,742 +23,25 @@ AtomVecCharge::AtomVecCharge(LAMMPS *lmp) : AtomVec(lmp) molecular = 0; mass_type = 1; - comm_x_only = comm_f_only = 1; - size_forward = 3; - size_reverse = 3; - size_border = 7; - size_velocity = 3; - size_data_atom = 6; - size_data_vel = 4; - xcol_data = 4; - atom->q_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecCharge::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - q = memory->grow(atom->q,nmax,"atom:q"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecCharge::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - q = atom->q; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecCharge::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - q[j] = q[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecCharge::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecCharge::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecCharge::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = q[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecCharge::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecCharge::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - q[i] = buf[m++]; - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecCharge::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = q[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecCharge::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - q[nlocal] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecCharge::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 12 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecCharge::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = q[i]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecCharge::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - q[nlocal] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecCharge::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - q[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecCharge::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - q[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecCharge::data_atom_hybrid(int nlocal, char **values) -{ - q[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecCharge::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = q[i]; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecCharge::pack_data_hybrid(int i, double *buf) -{ - buf[0] = q[i]; - return 1; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecCharge::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4],buf[i][5], - (int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i, - (int) ubuf(buf[i][8]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecCharge::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e",buf[0]); - return 1; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecCharge::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("q")) bytes += memory->usage(q,nmax); - return bytes; + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) "q"; + fields_copy = (char *) "q"; + fields_comm = NULL; + fields_comm_vel = NULL; + fields_reverse = NULL; + fields_border = (char *) "q"; + fields_border_vel = (char *) "q"; + fields_exchange = (char *) "q"; + fields_restart = (char *) "q"; + fields_create = (char *) "q"; + fields_data_atom = (char *) "id type q x"; + fields_data_vel = NULL; + + setup_fields(); } diff --git a/src/atom_vec_charge.h b/src/atom_vec_charge.h index 10f1d8d141..d52b4a068a 100644 --- a/src/atom_vec_charge.h +++ b/src/atom_vec_charge.h @@ -27,42 +27,6 @@ namespace LAMMPS_NS { class AtomVecCharge : public AtomVec { public: AtomVecCharge(class LAMMPS *); - virtual ~AtomVecCharge() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - - protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *q; }; } @@ -72,13 +36,4 @@ class AtomVecCharge : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - */ diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index 75136503ea..7a14ea26e6 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -5,7 +5,7 @@ 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 + certain rights in this software. This software is distributead under the GNU General Public License. See the README file in the top-level LAMMPS directory. @@ -14,15 +14,11 @@ #include "atom_vec_sphere.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" #include "modify.h" #include "fix.h" #include "fix_adapt.h" #include "math_const.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; using namespace MathConst; @@ -33,19 +29,29 @@ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) { molecular = 0; - comm_x_only = 1; - comm_f_only = 0; - size_forward = 3; - size_reverse = 6; - size_border = 8; - size_velocity = 6; - size_data_atom = 7; - size_data_vel = 7; - xcol_data = 5; - atom->sphere_flag = 1; atom->radius_flag = atom->rmass_flag = atom->omega_flag = atom->torque_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 the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) "radius rmass omega torque"; + fields_copy = (char *) "radius rmass omega"; + fields_comm = NULL; + fields_comm_vel = (char *) "omega"; + fields_reverse = (char *) "torque"; + fields_border = (char *) "radius rmass"; + fields_border_vel = (char *) "radius rmass omega"; + fields_exchange = (char *) "radius rmass omega"; + fields_restart = (char *) "radius rmass omega"; + fields_create = (char *) "radius rmass omega"; + fields_data_atom = (char *) "id type radius rmass x"; + fields_data_vel = (char *) "omega"; + + setup_fields(); } /* ---------------------------------------------------------------------- */ @@ -55,10 +61,11 @@ void AtomVecSphere::init() AtomVec::init(); // set radvary if particle diameters are time-varying due to fix adapt + // NOTE: change this to a atom_style sphere optional arg radvary = 0; - comm_x_only = 1; - size_forward = 3; + //comm_x_only = 1; + //size_forward = 3; for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"adapt") == 0) { @@ -69,1118 +76,42 @@ void AtomVecSphere::init() size_forward = 5; } } -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecSphere::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - radius = memory->grow(atom->radius,nmax,"atom:radius"); - rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); - omega = memory->grow(atom->omega,nmax,3,"atom:omega"); - torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecSphere::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - radius = atom->radius; rmass = atom->rmass; - omega = atom->omega; torque = atom->torque; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecSphere::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - radius[j] = radius[i]; - rmass[j] = rmass[i]; - omega[j][0] = omega[i][0]; - omega[j][1] = omega[i][1]; - omega[j][2] = omega[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - if (radvary == 0) { - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - - } else { - m = 0; - if (pbc_flag == 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]; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - } - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - if (radvary == 0) { - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } - } - - } else { - m = 0; - if (pbc_flag == 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]; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - if (radvary == 0) return 0; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSphere::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - if (radvary == 0) { - 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++]; - } - } else { - 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++]; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - } - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSphere::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - if (radvary == 0) { - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - } - } else { - 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++]; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - } - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - if (radvary == 0) return 0; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSphere::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::unpack_reverse_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSphere::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - - -/* ---------------------------------------------------------------------- */ - -void AtomVecSphere::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecSphere::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = radius[i]; - buf[m++] = rmass[i]; - buf[m++] = omega[i][0]; - buf[m++] = omega[i][1]; - buf[m++] = omega[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSphere::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - radius[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - omega[nlocal][0] = buf[m++]; - omega[nlocal][1] = buf[m++]; - omega[nlocal][2] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecSphere::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 16 * nlocal; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecSphere::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = radius[i]; - buf[m++] = rmass[i]; - buf[m++] = omega[i][0]; - buf[m++] = omega[i][1]; - buf[m++] = omega[i][2]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecSphere::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - radius[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - omega[nlocal][0] = buf[m++]; - omega[nlocal][1] = buf[m++]; - omega[nlocal][2] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; + //fields_comm = (char *) "radius rmass"; + //fields_comm_vel = (char *) "radius rmass"; } /* ---------------------------------------------------------------------- create one atom of itype at coord - set other values to defaults + modify what default AtomVec::create_atom() just created ------------------------------------------------------------------------- */ void AtomVecSphere::create_atom(int itype, double *coord) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); + AtomVec::create_atom(itype,coord); + int ilocal = atom->nlocal-1; - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - radius[nlocal] = 0.5; - rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal]; - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - - atom->nlocal++; + atom->radius[ilocal] = 0.5; + atom->rmass[ilocal] = 4.0*MY_PI/3.0 * 0.5*0.5*0.5; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + modify what default AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ void AtomVecSphere::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - radius[nlocal] = 0.5 * utils::numeric(FLERR,values[2],true,lmp); - if (radius[nlocal] < 0.0) - error->one(FLERR,"Invalid radius in Atoms section of data file"); - - double density = utils::numeric(FLERR,values[3],true,lmp); - if (density <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - if (radius[nlocal] == 0.0) rmass[nlocal] = density; - else - rmass[nlocal] = 4.0*MY_PI/3.0 * - radius[nlocal]*radius[nlocal]*radius[nlocal] * density; - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecSphere::data_atom_hybrid(int nlocal, char **values) -{ - radius[nlocal] = 0.5 * utils::numeric(FLERR,values[0],true,lmp); - if (radius[nlocal] < 0.0) - error->one(FLERR,"Invalid radius in Atoms section of data file"); - - double density = utils::numeric(FLERR,values[1],true,lmp); - if (density <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - if (radius[nlocal] == 0.0) rmass[nlocal] = density; - else - rmass[nlocal] = 4.0*MY_PI/3.0 * - radius[nlocal]*radius[nlocal]*radius[nlocal] * density; - - return 2; -} - -/* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file -------------------------------------------------------------------------- */ - -void AtomVecSphere::data_vel(int m, char **values) -{ - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - omega[m][0] = utils::numeric(FLERR,values[3],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[4],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[5],true,lmp); -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file -------------------------------------------------------------------------- */ - -int AtomVecSphere::data_vel_hybrid(int m, char **values) -{ - omega[m][0] = utils::numeric(FLERR,values[0],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[1],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[2],true,lmp); - return 3; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecSphere::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = 2.0*radius[i]; - if (radius[i] == 0.0) buf[i][3] = rmass[i]; - else - buf[i][3] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); - buf[i][4] = x[i][0]; - buf[i][5] = x[i][1]; - buf[i][6] = x[i][2]; - buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecSphere::pack_data_hybrid(int i, double *buf) -{ - buf[0] = 2.0*radius[i]; - if (radius[i] == 0.0) buf[1] = rmass[i]; - else buf[1] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); - return 2; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecSphere::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3], - buf[i][4],buf[i][5],buf[i][6], - (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i, - (int) ubuf(buf[i][9]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecSphere::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e",buf[0],buf[1]); - return 2; -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ - -void AtomVecSphere::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = omega[i][0]; - buf[i][5] = omega[i][1]; - buf[i][6] = omega[i][2]; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid velocity info for data file -------------------------------------------------------------------------- */ - -int AtomVecSphere::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = omega[i][0]; - buf[1] = omega[i][1]; - buf[2] = omega[i][2]; - return 3; -} - -/* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ - -void AtomVecSphere::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3], - buf[i][4],buf[i][5],buf[i][6]); -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file -------------------------------------------------------------------------- */ - -int AtomVecSphere::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]); - return 3; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecSphere::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); + AtomVec::data_atom(coord,imagetmp,values); + int ilocal = atom->nlocal-1; - if (atom->memcheck("radius")) bytes += memory->usage(radius,nmax); - if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); - if (atom->memcheck("omega")) bytes += memory->usage(omega,nmax,3); - if (atom->memcheck("torque")) - bytes += memory->usage(torque,nmax*comm->nthreads,3); + double radius = 0.5 * atom->radius[ilocal]; + atom->radius[ilocal] = radius; + if (radius > 0.0) + atom->rmass[ilocal] = + 4.0*MY_PI/3.0 * radius*radius*radius * atom->rmass[ilocal]; - return bytes; + if (atom->rmass[ilocal] <= 0.0) + error->one(FLERR,"Invalid mass in Atoms section of data file"); } diff --git a/src/atom_vec_sphere.h b/src/atom_vec_sphere.h index 28b1198d59..98762dba49 100644 --- a/src/atom_vec_sphere.h +++ b/src/atom_vec_sphere.h @@ -27,54 +27,11 @@ namespace LAMMPS_NS { class AtomVecSphere : public AtomVec { public: AtomVecSphere(class LAMMPS *); - ~AtomVecSphere() {} void init(); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); void create_atom(int, double *); void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); - bigint memory_usage(); private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *radius,*rmass; - double **omega,**torque; int radvary; }; @@ -85,15 +42,6 @@ class AtomVecSphere : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - E: Invalid radius in Atoms section of data file Radius must be >= 0.0. -- GitLab From 6c18e366d7d2972a1bf79e6e5f5bd0dd7c0bb6af Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 26 Nov 2019 18:34:51 -0700 Subject: [PATCH 007/577] changes to start to make atom style hybrid work --- src/DIPOLE/atom_vec_dipole.cpp | 12 +- src/DIPOLE/atom_vec_dipole.h | 2 +- src/MOLECULE/atom_vec_angle.cpp | 37 +- src/MOLECULE/atom_vec_angle.h | 8 +- src/MOLECULE/atom_vec_bond.cpp | 36 +- src/MOLECULE/atom_vec_bond.h | 8 +- src/MOLECULE/atom_vec_full.cpp | 43 +- src/MOLECULE/atom_vec_full.h | 9 +- src/MOLECULE/atom_vec_molecular.cpp | 43 +- src/MOLECULE/atom_vec_molecular.h | 9 +- src/MOLECULE/atom_vec_template.cpp | 17 +- src/MOLECULE/atom_vec_template.h | 4 +- src/PERI/atom_vec_peri.cpp | 14 +- src/PERI/atom_vec_peri.h | 2 +- src/SPIN/atom_vec_spin.cpp | 30 +- src/SPIN/atom_vec_spin.h | 2 +- src/atom.cpp | 1 + src/atom_vec.cpp | 490 +++++++------- src/atom_vec.h | 51 +- src/atom_vec_hybrid.cpp | 949 ++-------------------------- src/atom_vec_hybrid.h | 36 +- src/atom_vec_sphere.cpp | 80 ++- src/atom_vec_sphere.h | 8 +- src/special.cpp | 1 - 24 files changed, 523 insertions(+), 1369 deletions(-) diff --git a/src/DIPOLE/atom_vec_dipole.cpp b/src/DIPOLE/atom_vec_dipole.cpp index dc3279227d..650bc14d8f 100644 --- a/src/DIPOLE/atom_vec_dipole.cpp +++ b/src/DIPOLE/atom_vec_dipole.cpp @@ -55,16 +55,12 @@ AtomVecDipole::AtomVecDipole(LAMMPS *lmp) : AtomVec(lmp) } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what the default AtomVec::data_atom() just initialized + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecDipole::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecDipole::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - - int ilocal = atom->nlocal-1; - double mu = atom->mu[ilocal]; + double *mu = atom->mu[ilocal]; mu[3] = sqrt(mu[0]*mu[0] + mu[1]*mu[1] + mu[2]*mu[2]); } - diff --git a/src/DIPOLE/atom_vec_dipole.h b/src/DIPOLE/atom_vec_dipole.h index 6abcb4e2ea..45f33d109d 100644 --- a/src/DIPOLE/atom_vec_dipole.h +++ b/src/DIPOLE/atom_vec_dipole.h @@ -27,7 +27,7 @@ namespace LAMMPS_NS { class AtomVecDipole : public AtomVec { public: AtomVecDipole(class LAMMPS *); - void data_atom(double *, imageint, char **); + void data_atom_post(int); }; } diff --git a/src/MOLECULE/atom_vec_angle.cpp b/src/MOLECULE/atom_vec_angle.cpp index 79f5a7853e..df48c4b2a0 100644 --- a/src/MOLECULE/atom_vec_angle.cpp +++ b/src/MOLECULE/atom_vec_angle.cpp @@ -67,11 +67,10 @@ AtomVecAngle::~AtomVecAngle() } /* ---------------------------------------------------------------------- - pack atom I's data for restart file - modify/unmodify values for default AtomVec::pack_restart() to pack + modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecAngle::pack_restart(int i, double *buf) +void AtomVecAngle::pack_restart_pre(int i) { // insure negative vectors are needed length @@ -110,51 +109,49 @@ int AtomVecAngle::pack_restart(int i, double *buf) any_angle_negative = 1; } else angle_negative[m] = 0; } +} - // perform the pack with adjusted values - - int n = AtomVec::pack_restart(i,buf); +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_restart() +------------------------------------------------------------------------- */ +void AtomVecAngle::pack_restart_post(int i) +{ // restore the flagged types to their negative values if (any_bond_negative) { + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[i]; m++) if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } + if (any_angle_negative) { + int *num_angle = atom->num_angle; + int **angle_type = atom->angle_type; for (int m = 0; m < num_angle[i]; m++) if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; } - - return n; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - initialize other atom quantities + initialize other atom quantities after AtomVec::unpack_restart() ------------------------------------------------------------------------- */ -int AtomVecAngle::unpack_restart(double *buf) +void AtomVecAngle::unpack_restart_init(int ilocal) { - AtomVec::unpack_restart(buf); - int ilocal = atom->nlocal-1; - atom->nspecial[ilocal][0] = 0; atom->nspecial[ilocal][1] = 0; atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecAngle::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecAngle::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - atom->num_bond[ilocal] = 0; atom->num_angle[ilocal] = 0; atom->nspecial[ilocal][0] = 0; diff --git a/src/MOLECULE/atom_vec_angle.h b/src/MOLECULE/atom_vec_angle.h index 6511b517ee..48e55b0988 100644 --- a/src/MOLECULE/atom_vec_angle.h +++ b/src/MOLECULE/atom_vec_angle.h @@ -28,11 +28,13 @@ class AtomVecAngle : public AtomVec { public: AtomVecAngle(class LAMMPS *); ~AtomVecAngle(); - int pack_restart(int, double *); - int unpack_restart(double *); - void data_atom(double *, imageint, char **); + void pack_restart_pre(int); + void pack_restart_post(int); + void unpack_restart_init(int); + void data_atom_post(int); private: + int any_bond_negative,any_angle_negative; int bond_per_atom,angle_per_atom; int *bond_negative,*angle_negative; }; diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp index 20cdfdd65a..fd3f08979d 100644 --- a/src/MOLECULE/atom_vec_bond.cpp +++ b/src/MOLECULE/atom_vec_bond.cpp @@ -61,11 +61,10 @@ AtomVecBond::~AtomVecBond() } /* ---------------------------------------------------------------------- - pack atom I's data for restart file - modify/unmodify values for default AtomVec::pack_restart() to pack + modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecBond::pack_restart(int i, double *buf) +void AtomVecBond::pack_restart_pre(int i) { // insure bond_negative vector is needed length @@ -80,7 +79,7 @@ int AtomVecBond::pack_restart(int i, double *buf) int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; - int any_bond_negative = 0; + any_bond_negative = 0; for (int m = 0; m < num_bond[i]; m++) { if (bond_type[i][m] < 0) { bond_negative[m] = 1; @@ -88,47 +87,42 @@ int AtomVecBond::pack_restart(int i, double *buf) any_bond_negative = 1; } else bond_negative[m] = 0; } +} - // perform the pack with adjusted values - - int n = AtomVec::pack_restart(i,buf); +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_restart() +------------------------------------------------------------------------- */ +void AtomVecBond::pack_restart_post(int i) +{ // restore the flagged types to their negative values if (any_bond_negative) { + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[i]; m++) if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } - - return n; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - initialize other atom quantities + initialize other atom quantities after AtomVec::unpack_restart() ------------------------------------------------------------------------- */ -int AtomVecBond::unpack_restart(double *buf) +void AtomVecBond::unpack_restart_init(int ilocal) { - AtomVec::unpack_restart(buf); - int ilocal = atom->nlocal-1; - atom->nspecial[ilocal][0] = 0; atom->nspecial[ilocal][1] = 0; atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecBond::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecBond::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - atom->num_bond[ilocal] = 0; atom->nspecial[ilocal][0] = 0; atom->nspecial[ilocal][1] = 0; diff --git a/src/MOLECULE/atom_vec_bond.h b/src/MOLECULE/atom_vec_bond.h index 9245bc317a..c2bf7d6680 100644 --- a/src/MOLECULE/atom_vec_bond.h +++ b/src/MOLECULE/atom_vec_bond.h @@ -28,11 +28,13 @@ class AtomVecBond : public AtomVec { public: AtomVecBond(class LAMMPS *); ~AtomVecBond(); - int pack_restart(int, double *); - int unpack_restart(double *); - void data_atom(double *, imageint, char **); + void pack_restart_pre(int); + void pack_restart_post(int); + void unpack_restart_init(int); + void data_atom_post(int); private: + int any_bond_negative; int bond_per_atom; int *bond_negative; }; diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp index 826d5fea4e..ed838aa0e3 100644 --- a/src/MOLECULE/atom_vec_full.cpp +++ b/src/MOLECULE/atom_vec_full.cpp @@ -89,11 +89,10 @@ AtomVecFull::~AtomVecFull() } /* ---------------------------------------------------------------------- - pack atom I's data for restart file - modify/unmodify values for default AtomVec::pack_restart() to pack + modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecFull::pack_restart(int i, double *buf) +void AtomVecFull::pack_restart_pre(int i) { // insure negative vectors are needed length @@ -164,59 +163,63 @@ int AtomVecFull::pack_restart(int i, double *buf) any_improper_negative = 1; } else improper_negative[m] = 0; } +} - // perform the pack with adjusted values - - int n = AtomVec::pack_restart(i,buf); +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_restart() +------------------------------------------------------------------------- */ +void AtomVecFull::pack_restart_post(int i) +{ // restore the flagged types to their negative values if (any_bond_negative) { + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[i]; m++) if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } + if (any_angle_negative) { + int *num_angle = atom->num_angle; + int **angle_type = atom->angle_type; for (int m = 0; m < num_angle[i]; m++) if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; } + if (any_dihedral_negative) { + int *num_dihedral = atom->num_dihedral; + int **dihedral_type = atom->dihedral_type; for (int m = 0; m < num_dihedral[i]; m++) if (dihedral_negative[m]) dihedral_type[i][m] = -dihedral_type[i][m]; } + if (any_improper_negative) { + int *num_improper = atom->num_improper; + int **improper_type = atom->improper_type; for (int m = 0; m < num_improper[i]; m++) if (improper_negative[m]) improper_type[i][m] = -improper_type[i][m]; } - - return n; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - initialize other atom quantities + initialize other atom quantities after AtomVec::unpack_restart() ------------------------------------------------------------------------- */ -int AtomVecFull::unpack_restart(double *buf) +void AtomVecFull::unpack_restart_init(int ilocal) { - AtomVec::unpack_restart(buf); - int ilocal = atom->nlocal-1; - atom->nspecial[ilocal][0] = 0; atom->nspecial[ilocal][1] = 0; atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecFull::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecFull::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - atom->num_bond[ilocal] = 0; atom->num_angle[ilocal] = 0; atom->num_dihedral[ilocal] = 0; diff --git a/src/MOLECULE/atom_vec_full.h b/src/MOLECULE/atom_vec_full.h index b194a86994..455bbd0d5e 100644 --- a/src/MOLECULE/atom_vec_full.h +++ b/src/MOLECULE/atom_vec_full.h @@ -28,11 +28,14 @@ class AtomVecFull : public AtomVec { public: AtomVecFull(class LAMMPS *); ~AtomVecFull(); - int pack_restart(int, double *); - int unpack_restart(double *); - void data_atom(double *, imageint, char **); + void pack_restart_pre(int); + void pack_restart_post(int); + void unpack_restart_init(int); + void data_atom_post(int); private: + int any_bond_negative,any_angle_negative, + any_dihedral_negative,any_improper_negative; int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; int *bond_negative,*angle_negative,*dihedral_negative,*improper_negative; }; diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp index dad7c5cea6..77aec2cf50 100644 --- a/src/MOLECULE/atom_vec_molecular.cpp +++ b/src/MOLECULE/atom_vec_molecular.cpp @@ -89,11 +89,10 @@ AtomVecMolecular::~AtomVecMolecular() } /* ---------------------------------------------------------------------- - pack atom I's data for restart file - modify/unmodify values for default AtomVec::pack_restart() to pack + modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -int AtomVecMolecular::pack_restart(int i, double *buf) +void AtomVecMolecular::pack_restart_pre(int i) { // insure negative vectors are needed length @@ -164,59 +163,63 @@ int AtomVecMolecular::pack_restart(int i, double *buf) any_improper_negative = 1; } else improper_negative[m] = 0; } +} - // perform the pack with adjusted values - - int n = AtomVec::pack_restart(i,buf); +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_restart() +------------------------------------------------------------------------- */ +void AtomVecMolecular::pack_restart_post(int i) +{ // restore the flagged types to their negative values if (any_bond_negative) { + int *num_bond = atom->num_bond; + int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[i]; m++) if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; } + if (any_angle_negative) { + int *num_angle = atom->num_angle; + int **angle_type = atom->angle_type; for (int m = 0; m < num_angle[i]; m++) if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; } + if (any_dihedral_negative) { + int *num_dihedral = atom->num_dihedral; + int **dihedral_type = atom->dihedral_type; for (int m = 0; m < num_dihedral[i]; m++) if (dihedral_negative[m]) dihedral_type[i][m] = -dihedral_type[i][m]; } + if (any_improper_negative) { + int *num_improper = atom->num_improper; + int **improper_type = atom->improper_type; for (int m = 0; m < num_improper[i]; m++) if (improper_negative[m]) improper_type[i][m] = -improper_type[i][m]; } - - return n; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - initialize other atom quantities + initialize other atom quantities after AtomVec::unpack_restart() ------------------------------------------------------------------------- */ -int AtomVecMolecular::unpack_restart(double *buf) +void AtomVecMolecular::unpack_restart_init(int ilocal) { - AtomVec::unpack_restart(buf); - int ilocal = atom->nlocal-1; - atom->nspecial[ilocal][0] = 0; atom->nspecial[ilocal][1] = 0; atom->nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecMolecular::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecMolecular::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - atom->num_bond[ilocal] = 0; atom->num_angle[ilocal] = 0; atom->num_dihedral[ilocal] = 0; diff --git a/src/MOLECULE/atom_vec_molecular.h b/src/MOLECULE/atom_vec_molecular.h index cba6d1b480..5b79f8b5c6 100644 --- a/src/MOLECULE/atom_vec_molecular.h +++ b/src/MOLECULE/atom_vec_molecular.h @@ -28,11 +28,14 @@ class AtomVecMolecular : public AtomVec { public: AtomVecMolecular(class LAMMPS *); ~AtomVecMolecular(); - int pack_restart(int, double *); - int unpack_restart(double *); - void data_atom(double *, imageint, char **); + void pack_restart_pre(int); + void pack_restart_post(int); + void unpack_restart_init(int); + void data_atom_post(int); private: + int any_bond_negative,any_angle_negative, + any_dihedral_negative,any_improper_negative; int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; int *bond_negative,*angle_negative,*dihedral_negative,*improper_negative; }; diff --git a/src/MOLECULE/atom_vec_template.cpp b/src/MOLECULE/atom_vec_template.cpp index 31d9af4caf..d22e9abfb3 100644 --- a/src/MOLECULE/atom_vec_template.cpp +++ b/src/MOLECULE/atom_vec_template.cpp @@ -97,29 +97,22 @@ void AtomVecTemplate::process_args(int narg, char **arg) } /* ---------------------------------------------------------------------- - create one atom of itype at coord - modify what default AtomVec::create_atom() just created + initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecTemplate::create_atom(int itype, double *coord) +void AtomVecTemplate::create_atom_post(int ilocal) { - AtomVec::create_atom(itype,coord); - - int ilocal = atom->nlocal-1; atom->molindex[ilocal] = -1; atom->molatom[ilocal] = -1; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - error check what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecTemplate::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecTemplate::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - - int ilocal = atom->nlocal-1; int molindex = atom->molindex[ilocal]; int molatom = atom->molatom[ilocal]; diff --git a/src/MOLECULE/atom_vec_template.h b/src/MOLECULE/atom_vec_template.h index 59a1386f2d..52ef5e70e1 100644 --- a/src/MOLECULE/atom_vec_template.h +++ b/src/MOLECULE/atom_vec_template.h @@ -28,8 +28,8 @@ class AtomVecTemplate : public AtomVec { public: AtomVecTemplate(class LAMMPS *); void process_args(int, char **); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); + void create_atom_post(int); + void data_atom_post(int); }; } diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp index 29c4cb0d83..5450b23293 100644 --- a/src/PERI/atom_vec_peri.cpp +++ b/src/PERI/atom_vec_peri.cpp @@ -88,20 +88,16 @@ void AtomVecPeri::create_atom(int itype, double *coord) } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecPeri::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecPeri::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - atom->s0[ilocal] = DBL_MAX; - atom->x0[ilocal][0] = coord[0]; - atom->x0[ilocal][1] = coord[1]; - atom->x0[ilocal][2] = coord[2]; + atom->x0[ilocal][0] = atom->x[ilocal][0]; + atom->x0[ilocal][1] = atom->x[ilocal][1]; + atom->x0[ilocal][2] = atom->x[ilocal][2]; if (atom->rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid mass in Atoms section of data file"); diff --git a/src/PERI/atom_vec_peri.h b/src/PERI/atom_vec_peri.h index 12ef650348..3b41950a6f 100644 --- a/src/PERI/atom_vec_peri.h +++ b/src/PERI/atom_vec_peri.h @@ -28,7 +28,7 @@ class AtomVecPeri : public AtomVec { public: AtomVecPeri(class LAMMPS *); void create_atom(int, double *); - void data_atom(double *, imageint, char **); + void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); }; diff --git a/src/SPIN/atom_vec_spin.cpp b/src/SPIN/atom_vec_spin.cpp index 135f8936a1..6c88fb1a9e 100644 --- a/src/SPIN/atom_vec_spin.cpp +++ b/src/SPIN/atom_vec_spin.cpp @@ -62,30 +62,26 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked - or initialize other atom quantities + clear all forces (mechanical and magnetic) ------------------------------------------------------------------------- */ -void AtomVecSpin::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecSpin::force_clear(int /*n*/, size_t nbytes) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - - double *sp = atom->sp[ilocal]; - double inorm = 1.0/sqrt(sp[0]*sp[0] + sp[1]*sp[1] + sp[2]*sp[2]); - sp[0] *= inorm; - sp[1] *= inorm; - sp[2] *= inorm; + memset(&atom->f[0][0],0,3*nbytes); + memset(&atom->fm[0][0],0,3*nbytes); + memset(&atom->fm_long[0][0],0,3*nbytes); } /* ---------------------------------------------------------------------- - clear all forces (mech and mag) + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecSpin::force_clear(int /*n*/, size_t nbytes) +void AtomVecSpin::data_atom_post(int ilocal) { - memset(&atom->f[0][0],0,3*nbytes); - memset(&atom->fm[0][0],0,3*nbytes); - memset(&atom->fm_long[0][0],0,3*nbytes); + double *sp = atom->sp[ilocal]; + double inorm = 1.0/sqrt(sp[0]*sp[0] + sp[1]*sp[1] + sp[2]*sp[2]); + sp[0] *= inorm; + sp[1] *= inorm; + sp[2] *= inorm; } diff --git a/src/SPIN/atom_vec_spin.h b/src/SPIN/atom_vec_spin.h index ca92cccc2e..c68f3a0419 100644 --- a/src/SPIN/atom_vec_spin.h +++ b/src/SPIN/atom_vec_spin.h @@ -27,8 +27,8 @@ namespace LAMMPS_NS { class AtomVecSpin : public AtomVec { public: AtomVecSpin(class LAMMPS *); - void data_atom(double *, imageint, char **); void force_clear(int, size_t); + void data_atom_post(int); }; } diff --git a/src/atom.cpp b/src/atom.cpp index 7f1a5a6022..e1736e321c 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -2498,3 +2498,4 @@ bigint Atom::memory_usage() return bytes; } + diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index 428117f0db..776d7a4619 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -145,223 +145,6 @@ void AtomVec::init() error->all(FLERR,"KOKKOS package requires a kokkos enabled atom_style"); } -/* ---------------------------------------------------------------------- - process field strings to initialize data structs for all other methods -------------------------------------------------------------------------- */ - -void AtomVec::setup_fields() -{ - int n,cols; - - if (!fields_data_atom) - error->all(FLERR,"Atom style requires fields_data_atom"); - - // process field strings - // return # of fields and matching index into atom->peratom (in Method struct) - - ngrow = process_fields(fields_grow,default_grow,&mgrow); - ncopy = process_fields(fields_copy,default_copy,&mcopy); - ncomm = process_fields(fields_comm,default_comm,&mcomm); - ncomm_vel = process_fields(fields_comm_vel,default_comm_vel,&mcomm_vel); - nreverse = process_fields(fields_reverse,default_reverse,&mreverse); - nborder = process_fields(fields_border,default_border,&mborder); - nborder_vel = process_fields(fields_border_vel,default_border_vel,&mborder_vel); - nexchange = process_fields(fields_exchange,default_exchange,&mexchange); - nrestart = process_fields(fields_restart,default_restart,&mrestart); - ncreate = process_fields(fields_create,default_create,&mcreate); - ndata_atom = process_fields(fields_data_atom,default_data_atom,&mdata_atom); - ndata_vel = process_fields(fields_data_vel,default_data_vel,&mdata_vel); - - // populate field-based data struct for each method to use - - create_method(ngrow,&mgrow); - create_method(ncopy,&mcopy); - create_method(ncomm,&mcomm); - create_method(ncomm_vel,&mcomm_vel); - create_method(nreverse,&mreverse); - create_method(nborder,&mborder); - create_method(nborder_vel,&mborder_vel); - create_method(nexchange,&mexchange); - create_method(nrestart,&mrestart); - create_method(ncreate,&mcreate); - create_method(ndata_atom,&mdata_atom); - create_method(ndata_vel,&mdata_vel); - - // create threads data struct for grow and memory_usage to use - - threads = new int[ngrow]; - for (int i = 0; i < ngrow; i++) { - Atom::PerAtom *field = &atom->peratom[mgrow.index[i]]; - if (field->threadflag) threads[i] = nthreads; - else threads[i] = 1; - } - - // set style-specific variables - // NOTE: check for others vars in atom_vec.cpp/h ?? - - if (ncomm == 0) comm_x_only = 1; - else comm_x_only = 0; - - if (nreverse == 0) comm_f_only = 1; - else comm_f_only = 0; - - size_forward = 3; - for (n = 0; n < ncomm; n++) { - cols = mcomm.cols[n]; - if (cols == 0) size_forward++; - else size_forward += cols; - } - - size_reverse = 3; - for (n = 0; n < nreverse; n++) { - cols = mreverse.cols[n]; - if (cols == 0) size_reverse++; - else size_reverse += cols; - } - - size_border = 6; - for (n = 0; n < nborder; n++) { - cols = mborder.cols[n]; - if (cols == 0) size_border++; - else size_border += cols; - } - - size_velocity = 3; - for (n = 0; n < ncomm_vel; n++) { - cols = mcomm_vel.cols[n]; - if (cols == 0) size_velocity++; - else size_velocity += cols; - } - - size_data_atom = 0; - for (n = 0; n < ndata_atom; n++) { - cols = mdata_atom.cols[n]; - if (strcmp(atom->peratom[mdata_atom.index[n]].name,"x") == 0) - xcol_data = size_data_atom + 1; - if (cols == 0) size_data_atom++; - else size_data_atom += cols; - } - - size_data_vel = 4; - for (n = 0; n < ndata_vel; n++) { - cols = mdata_vel.cols[n]; - if (cols == 0) size_data_vel++; - else size_data_vel += cols; - } -} - -/* ---------------------------------------------------------------------- - process a single field string -------------------------------------------------------------------------- */ - -int AtomVec::process_fields(char *list, const char *default_list, Method *method) -{ - int i,n; - char match[128]; - - if (list == NULL) { - method->index = NULL; - return 0; - } - - // make copy of list of fields so can tokenize it - - n = strlen(list) + 1; - char *copy = new char[n]; - strcpy(copy,list); - - int nfield = atom->count_words(copy); - int *index = new int[nfield]; - - Atom::PerAtom *peratom = atom->peratom; - int nperatom = atom->nperatom; - - nfield = 0; - char *field = strtok(copy," "); - while (field) { - - // find field in master Atom::peratom list - - for (i = 0; i < nperatom; i++) - if (strcmp(field,peratom[i].name) == 0) break; - if (i == nperatom) error->all(FLERR,"Atom_style unrecognized peratom field"); - index[nfield++] = i; - - // error if field is in default list or appears multiple times - - sprintf(match," %s ",field); - if (strstr(default_list,match)) - error->all(FLERR,"Atom_style repeat of default peratom field"); - - for (i = 0; i < nfield-1; i++) - if (index[i] == index[nfield-1]) - error->all(FLERR,"Atom_style duplicated peratom field"); - - field = strtok(NULL," "); - } - - delete [] copy; - - method->index = index; - return nfield; -} - -/* ---------------------------------------------------------------------- - create a method data structs for processing fields -------------------------------------------------------------------------- */ - -void AtomVec::create_method(int nfield, Method *method) -{ - method->pdata = new void*[nfield]; - method->datatype = new int[nfield]; - method->cols = new int[nfield]; - method->maxcols = new int*[nfield]; - method->collength = new int[nfield]; - method->plength = new void*[nfield]; - - for (int i = 0; i < nfield; i++) { - Atom::PerAtom *field = &atom->peratom[method->index[i]]; - method->pdata[i] = (void *) field->address; - method->datatype[i] = field->datatype; - method->cols[i] = field->cols; - if (method->cols[i] < 0) { - method->maxcols[i] = field->address_maxcols; - method->collength[i] = field->collength; - method->plength[i] = field->address_length; - } - } -} - -/* ---------------------------------------------------------------------- - free memory in a method data structs -------------------------------------------------------------------------- */ - -void AtomVec::init_method(Method *method) -{ - method->pdata = NULL; - method->datatype = NULL; - method->cols = NULL; - method->maxcols = NULL; - method->collength = NULL; - method->plength = NULL; - method->index = NULL; -} - -/* ---------------------------------------------------------------------- - free memory in a method data structs -------------------------------------------------------------------------- */ - -void AtomVec::destroy_method(Method *method) -{ - delete [] method->pdata; - delete [] method->datatype; - delete [] method->cols; - delete [] method->maxcols; - delete [] method->collength; - delete [] method->plength; - delete [] method->index; -} - /* ---------------------------------------------------------------------- grow nmax so it is a multiple of DELTA ------------------------------------------------------------------------- */ @@ -446,18 +229,6 @@ void AtomVec::grow(int n) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); } -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVec::grow_reset() -{ - // NOTE: is this method needed anymore - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; -} - /* ---------------------------------------------------------------------- copy atom I info to atom J ------------------------------------------------------------------------- */ @@ -1614,6 +1385,10 @@ int AtomVec::pack_restart(int i, double *buf) int mm,nn,datatype,cols,collength,ncols; void *pdata,*plength; + // if needed, change values before packing + + pack_restart_pre(i); + int m = 1; buf[m++] = x[i][0]; buf[m++] = x[i][1]; @@ -1684,6 +1459,12 @@ int AtomVec::pack_restart(int i, double *buf) } } + // if needed, restore values after packing + + pack_restart_post(i); + + // invoke fixes which store peratom restart info + for (int iextra = 0; iextra < atom->nextra_restart; iextra++) m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); @@ -1777,6 +1558,12 @@ int AtomVec::unpack_restart(double *buf) } } + // if needed, initialize other peratom values + + unpack_restart_init(nlocal); + + // store extra restart info which fixes can unpack when instantiated + double **extra = atom->extra; if (atom->nextra_store) { int size = static_cast (buf[0]) - m; @@ -1812,7 +1599,7 @@ void AtomVec::create_atom(int itype, double *coord) v[nlocal][1] = 0.0; v[nlocal][2] = 0.0; - // special-case initialization for some fields + // initialization additional fields for (n = 0; n < ncreate; n++) { pdata = mcreate.pdata[n]; @@ -1848,12 +1635,16 @@ void AtomVec::create_atom(int itype, double *coord) } } + // if needed, initialize other peratom values + + create_atom_post(nlocal); + atom->nlocal++; } /* ---------------------------------------------------------------------- unpack one line from Atoms section of data file - initialize other atom quantities + initialize other peratom quantities ------------------------------------------------------------------------- */ void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) @@ -1919,6 +1710,10 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) if (atom->type[nlocal] <= 0 || atom->type[nlocal] > atom->ntypes) error->one(FLERR,"Invalid atom type in Atoms section of data file"); + // if needed, modify unpacked values or initialize other peratom values + + data_atom_post(nlocal); + atom->nlocal++; } @@ -1933,6 +1728,11 @@ void AtomVec::pack_data(double **buf) int nlocal = atom->nlocal; for (int i = 0; i < nlocal; i++) { + + // if needed, change values before packing + + pack_data_pre(i); + j = 0; for (n = 0; n < ndata_atom; n++) { pdata = mdata_atom.pdata[n]; @@ -1971,6 +1771,10 @@ void AtomVec::pack_data(double **buf) buf[i][j++] = ubuf((image[i] & IMGMASK) - IMGMAX).d; buf[i][j++] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; buf[i][j++] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; + + // if needed, restore values after packing + + pack_data_post(i); } } @@ -2493,3 +2297,227 @@ bigint AtomVec::memory_usage() return bytes; } + +// ---------------------------------------------------------------------- +// internal methods +// ---------------------------------------------------------------------- + +/* ---------------------------------------------------------------------- + process field strings to initialize data structs for all other methods +------------------------------------------------------------------------- */ + +void AtomVec::setup_fields() +{ + int n,cols; + + if (!fields_data_atom) + error->all(FLERR,"Atom style requires fields_data_atom"); + if (strstr(fields_data_atom,"id ") != fields_data_atom) + error->all(FLERR,"Atom style fields_data_atom must have id as first field"); + + // process field strings + // return # of fields and matching index into atom->peratom (in Method struct) + + ngrow = process_fields(fields_grow,default_grow,&mgrow); + ncopy = process_fields(fields_copy,default_copy,&mcopy); + ncomm = process_fields(fields_comm,default_comm,&mcomm); + ncomm_vel = process_fields(fields_comm_vel,default_comm_vel,&mcomm_vel); + nreverse = process_fields(fields_reverse,default_reverse,&mreverse); + nborder = process_fields(fields_border,default_border,&mborder); + nborder_vel = process_fields(fields_border_vel,default_border_vel,&mborder_vel); + nexchange = process_fields(fields_exchange,default_exchange,&mexchange); + nrestart = process_fields(fields_restart,default_restart,&mrestart); + ncreate = process_fields(fields_create,default_create,&mcreate); + ndata_atom = process_fields(fields_data_atom,default_data_atom,&mdata_atom); + ndata_vel = process_fields(fields_data_vel,default_data_vel,&mdata_vel); + + // populate field-based data struct for each method to use + + create_method(ngrow,&mgrow); + create_method(ncopy,&mcopy); + create_method(ncomm,&mcomm); + create_method(ncomm_vel,&mcomm_vel); + create_method(nreverse,&mreverse); + create_method(nborder,&mborder); + create_method(nborder_vel,&mborder_vel); + create_method(nexchange,&mexchange); + create_method(nrestart,&mrestart); + create_method(ncreate,&mcreate); + create_method(ndata_atom,&mdata_atom); + create_method(ndata_vel,&mdata_vel); + + // create threads data struct for grow and memory_usage to use + + threads = new int[ngrow]; + for (int i = 0; i < ngrow; i++) { + Atom::PerAtom *field = &atom->peratom[mgrow.index[i]]; + if (field->threadflag) threads[i] = nthreads; + else threads[i] = 1; + } + + // set style-specific variables + // NOTE: check for others vars in atom_vec.cpp/h ?? + // NOTE: need to set maxexchange, e.g for style hybrid? + + if (ncomm == 0) comm_x_only = 1; + else comm_x_only = 0; + + if (nreverse == 0) comm_f_only = 1; + else comm_f_only = 0; + + size_forward = 3; + for (n = 0; n < ncomm; n++) { + cols = mcomm.cols[n]; + if (cols == 0) size_forward++; + else size_forward += cols; + } + + size_reverse = 3; + for (n = 0; n < nreverse; n++) { + cols = mreverse.cols[n]; + if (cols == 0) size_reverse++; + else size_reverse += cols; + } + + size_border = 6; + for (n = 0; n < nborder; n++) { + cols = mborder.cols[n]; + if (cols == 0) size_border++; + else size_border += cols; + } + + size_velocity = 3; + for (n = 0; n < ncomm_vel; n++) { + cols = mcomm_vel.cols[n]; + if (cols == 0) size_velocity++; + else size_velocity += cols; + } + + size_data_atom = 0; + for (n = 0; n < ndata_atom; n++) { + cols = mdata_atom.cols[n]; + if (strcmp(atom->peratom[mdata_atom.index[n]].name,"x") == 0) + xcol_data = size_data_atom + 1; + if (cols == 0) size_data_atom++; + else size_data_atom += cols; + } + + size_data_vel = 4; + for (n = 0; n < ndata_vel; n++) { + cols = mdata_vel.cols[n]; + if (cols == 0) size_data_vel++; + else size_data_vel += cols; + } +} + +/* ---------------------------------------------------------------------- + process a single field string +------------------------------------------------------------------------- */ + +int AtomVec::process_fields(char *list, const char *default_list, Method *method) +{ + int i,n; + char match[128]; + + if (list == NULL) { + method->index = NULL; + return 0; + } + + // make copy of list of fields so can tokenize it + + n = strlen(list) + 1; + char *copy = new char[n]; + strcpy(copy,list); + + int nfield = atom->count_words(copy); + int *index = new int[nfield]; + + Atom::PerAtom *peratom = atom->peratom; + int nperatom = atom->nperatom; + + nfield = 0; + char *field = strtok(copy," "); + while (field) { + + // find field in master Atom::peratom list + + for (i = 0; i < nperatom; i++) + if (strcmp(field,peratom[i].name) == 0) break; + if (i == nperatom) error->all(FLERR,"Atom_style unrecognized peratom field"); + index[nfield++] = i; + + // error if field is in default list or appears multiple times + + sprintf(match," %s ",field); + if (strstr(default_list,match)) + error->all(FLERR,"Atom_style repeat of default peratom field"); + + for (i = 0; i < nfield-1; i++) + if (index[i] == index[nfield-1]) + error->all(FLERR,"Atom_style duplicated peratom field"); + + field = strtok(NULL," "); + } + + delete [] copy; + + method->index = index; + return nfield; +} + +/* ---------------------------------------------------------------------- + create a method data structs for processing fields +------------------------------------------------------------------------- */ + +void AtomVec::create_method(int nfield, Method *method) +{ + method->pdata = new void*[nfield]; + method->datatype = new int[nfield]; + method->cols = new int[nfield]; + method->maxcols = new int*[nfield]; + method->collength = new int[nfield]; + method->plength = new void*[nfield]; + + for (int i = 0; i < nfield; i++) { + Atom::PerAtom *field = &atom->peratom[method->index[i]]; + method->pdata[i] = (void *) field->address; + method->datatype[i] = field->datatype; + method->cols[i] = field->cols; + if (method->cols[i] < 0) { + method->maxcols[i] = field->address_maxcols; + method->collength[i] = field->collength; + method->plength[i] = field->address_length; + } + } +} + +/* ---------------------------------------------------------------------- + free memory in a method data structs +------------------------------------------------------------------------- */ + +void AtomVec::init_method(Method *method) +{ + method->pdata = NULL; + method->datatype = NULL; + method->cols = NULL; + method->maxcols = NULL; + method->collength = NULL; + method->plength = NULL; + method->index = NULL; +} + +/* ---------------------------------------------------------------------- + free memory in a method data structs +------------------------------------------------------------------------- */ + +void AtomVec::destroy_method(Method *method) +{ + delete [] method->pdata; + delete [] method->datatype; + delete [] method->cols; + delete [] method->maxcols; + delete [] method->collength; + delete [] method->plength; + delete [] method->index; +} diff --git a/src/atom_vec.h b/src/atom_vec.h index c3551b541d..8ed6fff35f 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -49,60 +49,68 @@ class AtomVec : protected Pointers { int nargcopy; // copy of command-line args for atom_style command char **argcopy; // used when AtomVec is realloced (restart,replicate) + // additional list of peratom fields operated on by different methods + // set by child styles + + char *fields_grow,*fields_copy; + char *fields_comm,*fields_comm_vel,*fields_reverse; + char *fields_border,*fields_border_vel; + char *fields_exchange,*fields_restart; + char *fields_create,*fields_data_atom,*fields_data_vel; + + // methods + AtomVec(class LAMMPS *); virtual ~AtomVec(); void store_args(int, char **); virtual void process_args(int, char **); virtual void init(); + virtual void force_clear(int, size_t) {} + void grow(int); - void grow_reset(); void copy(int, int, int); void clear_bonus() {} - void force_clear(int, size_t) {} int pack_comm(int, int *, double *, int, int *); int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *) {return 0;} void unpack_comm(int, int, double *); void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *) {return 0;} int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *) {return 0;} void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *) {return 0;} int pack_border(int, int *, double *, int, int *); int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *) {return 0;} void unpack_border(int, int, double *); void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *) {return 0;} int pack_exchange(int, double *); int unpack_exchange(double *); int size_restart(); - virtual int pack_restart(int, double *); - virtual int unpack_restart(double *); + virtual void pack_restart_pre(int) {} + int pack_restart(int, double *); + virtual void pack_restart_post(int) {} + int unpack_restart(double *); + virtual void unpack_restart_init(int) {} - virtual void create_atom(int, double *); + void create_atom(int, double *); + virtual void create_atom_post(int) {} + + void data_atom(double *, imageint, char **); + virtual void data_atom_post(int) {} - virtual void data_atom(double *, imageint, char **); void data_atom_bonus(int, char **) {} - int data_atom_hybrid(int, char **) {return 0;} void data_vel(int, char **); - int data_vel_hybrid(int, char **) {return 0;} + virtual void pack_data_pre(int) {} void pack_data(double **); + virtual void pack_data_post(int) {} int pack_data_hybrid(int, double *) {return 0;} void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *) {return 0;} void pack_vel(double **); - int pack_vel_hybrid(int, double *) {return 0;} void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *) {return 0;} int pack_bond(tagint **); void write_bond(FILE *, int, tagint **, int); @@ -129,18 +137,15 @@ class AtomVec : protected Pointers { imageint *image; double **x,**v,**f; + // standard list of peratom fields always operated on by different methods + // common to all styles, so not listed in field strings + const char *default_grow,*default_copy; const char *default_comm,*default_comm_vel,*default_reverse; const char *default_border,*default_border_vel; const char *default_exchange,*default_restart; const char *default_create,*default_data_atom,*default_data_vel; - char *fields_grow,*fields_copy; - char *fields_comm,*fields_comm_vel,*fields_reverse; - char *fields_border,*fields_border_vel; - char *fields_exchange,*fields_restart; - char *fields_create,*fields_data_atom,*fields_data_vel; - struct Method { void **pdata; int *datatype; diff --git a/src/atom_vec_hybrid.cpp b/src/atom_vec_hybrid.cpp index 4ca0dfbba5..d96494544c 100644 --- a/src/atom_vec_hybrid.cpp +++ b/src/atom_vec_hybrid.cpp @@ -35,6 +35,15 @@ AtomVecHybrid::~AtomVecHybrid() delete [] styles; for (int k = 0; k < nstyles; k++) delete [] keywords[k]; delete [] keywords; + + // these strings will be concatenated from sub-style strings + // fields_data_atom must start with fields common to all styles + + fields_grow = fields_copy = fields_comm = fields_comm_vel = NULL; + fields_reverse = fields_border = fields_border_vel = NULL; + fields_exchange = fields_restart = fields_create = NULL; + fields_data_atom = (char *) "id type x"; + fields_data_vel = NULL; } /* ---------------------------------------------------------------------- @@ -81,930 +90,65 @@ void AtomVecHybrid::process_args(int narg, char **arg) for (int i = 0; i < nallstyles; i++) delete [] allstyles[i]; delete [] allstyles; - // hybrid settings are MAX or MIN of sub-style settings - // hybrid sizes are minimal values plus extra values for each sub-style - - molecular = 0; - comm_x_only = comm_f_only = 1; - - size_forward = 3; - size_reverse = 3; - size_border = 6; - size_data_atom = 5; - size_data_vel = 4; - xcol_data = 3; - maxexchange = 0; - - for (int k = 0; k < nstyles; k++) { - if ((styles[k]->molecular == 1 && molecular == 2) || - (styles[k]->molecular == 2 && molecular == 1)) - error->all(FLERR,"Cannot mix molecular and molecule template " - "atom styles"); - molecular = MAX(molecular,styles[k]->molecular); - - bonds_allow = MAX(bonds_allow,styles[k]->bonds_allow); - angles_allow = MAX(angles_allow,styles[k]->angles_allow); - dihedrals_allow = MAX(dihedrals_allow,styles[k]->dihedrals_allow); - impropers_allow = MAX(impropers_allow,styles[k]->impropers_allow); - mass_type = MAX(mass_type,styles[k]->mass_type); - dipole_type = MAX(dipole_type,styles[k]->dipole_type); - forceclearflag = MAX(forceclearflag,styles[k]->forceclearflag); - - if (styles[k]->molecular == 2) onemols = styles[k]->onemols; - - comm_x_only = MIN(comm_x_only,styles[k]->comm_x_only); - comm_f_only = MIN(comm_f_only,styles[k]->comm_f_only); - size_forward += styles[k]->size_forward - 3; - size_reverse += styles[k]->size_reverse - 3; - size_border += styles[k]->size_border - 6; - size_data_atom += styles[k]->size_data_atom - 5; - size_data_vel += styles[k]->size_data_vel - 4; - - maxexchange += styles[k]->maxexchange; - } - - size_velocity = 3; - if (atom->omega_flag) size_velocity += 3; - if (atom->angmom_flag) size_velocity += 3; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecHybrid::init() -{ - AtomVec::init(); - for (int k = 0; k < nstyles; k++) styles[k]->init(); -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecHybrid::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - // sub-styles perform all reallocation - // turn off nextra_grow so hybrid can do that once below - - int tmp = atom->nextra_grow; - atom->nextra_grow = 0; - for (int k = 0; k < nstyles; k++) styles[k]->grow(nmax); - atom->nextra_grow = tmp; - - // insure hybrid local ptrs and sub-style ptrs are up to date - // for sub-styles, do this in case - // multiple sub-style reallocs of same array occurred - - grow_reset(); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecHybrid::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - omega = atom->omega; angmom = atom->angmom; - - for (int k = 0; k < nstyles; k++) styles[k]->grow_reset(); -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J for all sub-styles -------------------------------------------------------------------------- */ - -void AtomVecHybrid::copy(int i, int j, int delflag) -{ - int tmp = atom->nextra_grow; - atom->nextra_grow = 0; - for (int k = 0; k < nstyles; k++) styles[k]->copy(i,j,delflag); - atom->nextra_grow = tmp; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecHybrid::clear_bonus() -{ - for (int k = 0; k < nstyles; k++) styles[k]->clear_bonus(); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecHybrid::force_clear(int n, size_t nbytes) -{ - for (int k = 0; k < nstyles; k++) - if (styles[k]->forceclearflag) styles[k]->force_clear(n,nbytes); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecHybrid::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,k,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - } - } - - // pack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_comm_hybrid(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecHybrid::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,k,m; - double dx,dy,dz,dvx,dvy,dvz; - int omega_flag = atom->omega_flag; - int angmom_flag = atom->angmom_flag; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - if (omega_flag) { - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - if (angmom_flag) { - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - if (omega_flag) { - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - if (angmom_flag) { - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - if (omega_flag) { - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - if (angmom_flag) { - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - } - - // pack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_comm_hybrid(n,list,&buf[m]); - - return m; -} + // concatenate field strings from all sub-styles -/* ---------------------------------------------------------------------- */ + concatenate_fields(); -void AtomVecHybrid::unpack_comm(int n, int first, double *buf) -{ - int i,k,m,last; - - 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++]; - } + // parent AtomVec will now operate on concatenated fields - // unpack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->unpack_comm_hybrid(n,first,&buf[m]); + setup_fields(); } /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::unpack_comm_vel(int n, int first, double *buf) +void AtomVecHybrid::concatenate_fields() { - int i,k,m,last; - int omega_flag = atom->omega_flag; - int angmom_flag = atom->angmom_flag; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - if (omega_flag) { - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - } - if (angmom_flag) { - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; - } - } - - // unpack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->unpack_comm_hybrid(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecHybrid::pack_reverse(int n, int first, double *buf) -{ - int i,k,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - - // pack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_reverse_hybrid(n,first,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecHybrid::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,k,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } - - // unpack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->unpack_reverse_hybrid(n,list,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecHybrid::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,k,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - } + for (int k = 0; k < nstyles; k++) { + concatenate(fields_grow,styles[k]->fields_grow); + concatenate(fields_copy,styles[k]->fields_copy); + concatenate(fields_comm,styles[k]->fields_comm); + concatenate(fields_comm_vel,styles[k]->fields_comm_vel); + concatenate(fields_reverse,styles[k]->fields_reverse); + concatenate(fields_border,styles[k]->fields_border); + concatenate(fields_border_vel,styles[k]->fields_border_vel); + concatenate(fields_exchange,styles[k]->fields_exchange); + concatenate(fields_restart,styles[k]->fields_restart); + concatenate(fields_create,styles[k]->fields_create); + concatenate(fields_data_atom,styles[k]->fields_data_atom); + concatenate(fields_data_vel,styles[k]->fields_data_vel); } - - // pack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_border_hybrid(n,list,&buf[m]); - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; } /* ---------------------------------------------------------------------- */ -int AtomVecHybrid::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) +void AtomVecHybrid::concatenate(char *&root, char *add) { - int i,j,k,m; - double dx,dy,dz,dvx,dvy,dvz; - int omega_flag = atom->omega_flag; - int angmom_flag = atom->angmom_flag; + /* + char **rootwords,**addwords; + int nroot = parse(root,rootwords); + int nadd = parse(add,addwords); - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - if (omega_flag) { - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - if (angmom_flag) { - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - if (omega_flag) { - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - if (angmom_flag) { - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - if (omega_flag) { - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - if (angmom_flag) { - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } + for (int iadd = 0; iadd < nadd; iadd++) { + if (check(addwords[iadd],nroot,rootwords)) continue; + addone(addwords[iadd],nroot,rootwords); } - - // pack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_border_hybrid(n,list,&buf[m]); - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; + */ } /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::unpack_border(int n, int first, double *buf) +void AtomVecHybrid::init() { - int i,k,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - } - - // unpack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->unpack_border_hybrid(n,first,&buf[m]); - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); + AtomVec::init(); + for (int k = 0; k < nstyles; k++) styles[k]->init(); } /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::unpack_border_vel(int n, int first, double *buf) -{ - int i,k,m,last; - int omega_flag = atom->omega_flag; - int angmom_flag = atom->angmom_flag; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - if (omega_flag) { - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - } - if (angmom_flag) { - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; - } - } - - // unpack sub-style contributions as contiguous chunks - - for (k = 0; k < nstyles; k++) - m += styles[k]->unpack_border_hybrid(n,first,&buf[m]); - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - pack each sub-style one after the other -------------------------------------------------------------------------- */ - -int AtomVecHybrid::pack_exchange(int i, double *buf) -{ - int k,m; - - int tmp = atom->nextra_grow; - atom->nextra_grow = 0; - - m = 0; - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_exchange(i,&buf[m]); - - atom->nextra_grow = tmp; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for single atom received from another proc - unpack each sub-style one after the other - grow() occurs here so arrays for all sub-styles are grown -------------------------------------------------------------------------- */ - -int AtomVecHybrid::unpack_exchange(double *buf) -{ - int k,m; - - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int tmp = atom->nextra_grow; - atom->nextra_grow = 0; - - m = 0; - for (k = 0; k < nstyles; k++) { - m += styles[k]->unpack_exchange(&buf[m]); - atom->nlocal--; - } - - atom->nextra_grow = tmp; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecHybrid::size_restart() -{ - int tmp = atom->nextra_restart; - atom->nextra_restart = 0; - - int n = 0; - for (int k = 0; k < nstyles; k++) - n += styles[k]->size_restart(); - - atom->nextra_restart = tmp; - - int nlocal = atom->nlocal; - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (int i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - pack each sub-style one after the other -------------------------------------------------------------------------- */ - -int AtomVecHybrid::pack_restart(int i, double *buf) -{ - int tmp = atom->nextra_restart; - atom->nextra_restart = 0; - - int m = 0; - for (int k = 0; k < nstyles; k++) - m += styles[k]->pack_restart(i,&buf[m]); - - atom->nextra_restart = tmp; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - unpack each sub-style one after the other - grow() occurs here so arrays for all sub-styles are grown -------------------------------------------------------------------------- */ - -int AtomVecHybrid::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int tmp = atom->nextra_store; - atom->nextra_store = 0; - - int m = 0; - for (int k = 0; k < nstyles; k++) { - m += styles[k]->unpack_restart(&buf[m]); - atom->nlocal--; - } - atom->nextra_store = tmp; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - create each sub-style one after the other - grow() occurs here so arrays for all sub-styles are grown -------------------------------------------------------------------------- */ - -void AtomVecHybrid::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - for (int k = 0; k < nstyles; k++) { - styles[k]->create_atom(itype,coord); - atom->nlocal--; - } - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - grow() occurs here so arrays for all sub-styles are grown -------------------------------------------------------------------------- */ - -void AtomVecHybrid::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - mask[nlocal] = 1; - - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - if (atom->omega_flag) { - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - } - if (atom->angmom_flag) { - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - } - - // each sub-style parses sub-style specific values - - int m = 5; - for (int k = 0; k < nstyles; k++) - m += styles[k]->data_atom_hybrid(nlocal,&values[m]); - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file -------------------------------------------------------------------------- */ - -void AtomVecHybrid::data_vel(int m, char **values) +void AtomVecHybrid::force_clear(int n, size_t nbytes) { - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - - // each sub-style parses sub-style specific values - - int n = 3; for (int k = 0; k < nstyles; k++) - n += styles[k]->data_vel_hybrid(m,&values[n]); -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecHybrid::pack_data(double **buf) -{ - int k,m; - - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = x[i][0]; - buf[i][3] = x[i][1]; - buf[i][4] = x[i][2]; - - m = 5; - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_data_hybrid(i,&buf[i][m]); - - buf[i][m] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][m+1] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][m+2] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecHybrid::write_data(FILE *fp, int n, double **buf) -{ - int k,m; - - for (int i = 0; i < n; i++) { - fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4]); - - m = 5; - for (k = 0; k < nstyles; k++) - m += styles[k]->write_data_hybrid(fp,&buf[i][m]); - - fprintf(fp," %d %d %d\n", - (int) ubuf(buf[i][m]).i,(int) ubuf(buf[i][m+1]).i, - (int) ubuf(buf[i][m+2]).i); - } -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ - -void AtomVecHybrid::pack_vel(double **buf) -{ - int k,m; - - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - - m = 4; - for (k = 0; k < nstyles; k++) - m += styles[k]->pack_vel_hybrid(i,&buf[i][m]); - } -} - -/* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ - -void AtomVecHybrid::write_vel(FILE *fp, int n, double **buf) -{ - int k,m; - - for (int i = 0; i < n; i++) { - fprintf(fp,TAGINT_FORMAT " %g %g %g", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]); - - m = 4; - for (k = 0; k < nstyles; k++) - m += styles[k]->write_vel_hybrid(fp,&buf[i][m]); - - fprintf(fp,"\n"); - } + if (styles[k]->forceclearflag) styles[k]->force_clear(n,nbytes); } /* ---------------------------------------------------------------------- @@ -1073,14 +217,3 @@ int AtomVecHybrid::known_style(char *str) if (strcmp(str,allstyles[i]) == 0) return 1; return 0; } - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecHybrid::memory_usage() -{ - bigint bytes = 0; - for (int k = 0; k < nstyles; k++) bytes += styles[k]->memory_usage(); - return bytes; -} diff --git a/src/atom_vec_hybrid.h b/src/atom_vec_hybrid.h index 8129baccba..41067d44f2 100644 --- a/src/atom_vec_hybrid.h +++ b/src/atom_vec_hybrid.h @@ -34,48 +34,16 @@ class AtomVecHybrid : public AtomVec { ~AtomVecHybrid(); void process_args(int, char **); void init(); - void grow(int); - void grow_reset(); - void copy(int, int, int); - void clear_bonus(); void force_clear(int, size_t); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **) {return 0;} - void data_vel(int, char **); - void pack_data(double **); - void write_data(FILE *, int, double **); - void pack_vel(double **); - void write_vel(FILE *, int, double **); int property_atom(char *); void pack_property_atom(int, double *, int, int); - bigint memory_usage(); private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double **omega,**angmom; - int nallstyles; char **allstyles; + void concatenate_fields(); + void concatenate(char *&, char *); void build_styles(); int known_style(char *); }; diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index 7a14ea26e6..b44aa69035 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -19,6 +19,7 @@ #include "fix_adapt.h" #include "math_const.h" #include "error.h" +#include "utils.h" using namespace LAMMPS_NS; using namespace MathConst; @@ -54,58 +55,61 @@ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) setup_fields(); } +/* ---------------------------------------------------------------------- + process sub-style args + optional arg = 0/1 for static/dynamic particle radii +------------------------------------------------------------------------- */ + +void AtomVecSphere::process_args(int narg, char **arg) +{ + if (narg == 0) return; + if (narg != 1) error->all(FLERR,"Illegal atom_style sphere command"); + + radvary = utils::numeric(FLERR,arg[0],true,lmp); + if (radvary < 0 || radvary > 1) + error->all(FLERR,"Illegal atom_style sphere command"); + if (radvary == 0) return; + + // dynamic particle radius and mass must be communicated every step + + fields_comm = (char *) "radius rmass"; + fields_comm_vel = (char *) "radius rmass omega"; +} + /* ---------------------------------------------------------------------- */ void AtomVecSphere::init() { AtomVec::init(); - // set radvary if particle diameters are time-varying due to fix adapt - // NOTE: change this to a atom_style sphere optional arg - - radvary = 0; - //comm_x_only = 1; - //size_forward = 3; + // check if optional radvary setting should have been set to 1 for (int i = 0; i < modify->nfix; i++) if (strcmp(modify->fix[i]->style,"adapt") == 0) { FixAdapt *fix = (FixAdapt *) modify->fix[i]; - if (fix->diamflag) { - radvary = 1; - comm_x_only = 0; - size_forward = 5; - } + if (fix->diamflag && radvary == 0) + error->all(FLERR,"Fix adapt changes particle radii " + "but atom_style sphere is not dynamic"); } - - //fields_comm = (char *) "radius rmass"; - //fields_comm_vel = (char *) "radius rmass"; } /* ---------------------------------------------------------------------- - create one atom of itype at coord - modify what default AtomVec::create_atom() just created + initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecSphere::create_atom(int itype, double *coord) +void AtomVecSphere::create_atom_post(int ilocal) { - AtomVec::create_atom(itype,coord); - int ilocal = atom->nlocal-1; - atom->radius[ilocal] = 0.5; atom->rmass[ilocal] = 4.0*MY_PI/3.0 * 0.5*0.5*0.5; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - modify what default AtomVec::data_atom() just unpacked + modify what AtomVec::data_atom() just unpacked or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecSphere::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecSphere::data_atom_post(int ilocal) { - AtomVec::data_atom(coord,imagetmp,values); - int ilocal = atom->nlocal-1; - double radius = 0.5 * atom->radius[ilocal]; atom->radius[ilocal] = radius; if (radius > 0.0) @@ -115,3 +119,27 @@ void AtomVecSphere::data_atom(double *coord, imageint imagetmp, char **values) if (atom->rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid mass in Atoms section of data file"); } + +/* ---------------------------------------------------------------------- + modify values for AtomVec::pack_data() to pack +------------------------------------------------------------------------- */ + +void AtomVecSphere::pack_data_pre(int ilocal) +{ + radius = atom->radius[ilocal]; + rmass = atom->rmass[ilocal]; + + atom->radius[ilocal] *= 2.0; + if (radius == 0.0) + atom->rmass[ilocal] = rmass / (4.0*MY_PI/3.0 * radius*radius*radius); +} + +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_data() +------------------------------------------------------------------------- */ + +void AtomVecSphere::pack_data_post(int ilocal) +{ + atom->radius[ilocal] = radius; + atom->rmass[ilocal] = rmass; +} diff --git a/src/atom_vec_sphere.h b/src/atom_vec_sphere.h index 98762dba49..c205ba43de 100644 --- a/src/atom_vec_sphere.h +++ b/src/atom_vec_sphere.h @@ -27,12 +27,16 @@ namespace LAMMPS_NS { class AtomVecSphere : public AtomVec { public: AtomVecSphere(class LAMMPS *); + void process_args(int, char **); void init(); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); + void create_atom_post(int); + void data_atom_post(int); + void pack_data_pre(int); + void pack_data_post(int); private: int radvary; + double radius,rmass; }; } diff --git a/src/special.cpp b/src/special.cpp index 3dd817bc7f..f859f4ff53 100644 --- a/src/special.cpp +++ b/src/special.cpp @@ -715,7 +715,6 @@ void Special::combine() memory->create(atom->special,atom->nmax,atom->maxspecial,"atom:special"); } - atom->avec->grow_reset(); tagint **special = atom->special; // ---------------------------------------------------- -- GitLab From 4f6cb135920c7788b8501b96155678430740172e Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 27 Nov 2019 16:03:50 -0700 Subject: [PATCH 008/577] added atom styles with bonus data, also a few USER packages --- src/MOLECULE/atom_vec_template.cpp | 2 +- src/PERI/atom_vec_peri.cpp | 14 +- src/PERI/atom_vec_peri.h | 2 +- src/USER-DPD/atom_vec_dpd.cpp | 921 +---------------- src/USER-DPD/atom_vec_dpd.h | 51 +- src/USER-EFF/atom_vec_electron.cpp | 954 +----------------- src/USER-EFF/atom_vec_electron.h | 49 +- src/USER-MESO/atom_vec_edpd.cpp | 819 +--------------- src/USER-MESO/atom_vec_edpd.h | 34 +- src/atom.cpp | 30 +- src/atom.h | 15 +- src/atom_vec.cpp | 50 +- src/atom_vec.h | 41 +- src/atom_vec_body.cpp | 1179 +++------------------- src/atom_vec_body.h | 72 +- src/atom_vec_ellipsoid.cpp | 1170 +++------------------- src/atom_vec_ellipsoid.h | 69 +- src/atom_vec_line.cpp | 1111 +++------------------ src/atom_vec_line.h | 70 +- src/atom_vec_sphere.cpp | 4 +- src/atom_vec_tri.cpp | 1473 ++++------------------------ src/atom_vec_tri.h | 70 +- src/read_data.cpp | 6 +- src/read_data.h | 2 +- 24 files changed, 923 insertions(+), 7285 deletions(-) diff --git a/src/MOLECULE/atom_vec_template.cpp b/src/MOLECULE/atom_vec_template.cpp index d22e9abfb3..f8f99ae8a8 100644 --- a/src/MOLECULE/atom_vec_template.cpp +++ b/src/MOLECULE/atom_vec_template.cpp @@ -97,7 +97,7 @@ void AtomVecTemplate::process_args(int narg, char **arg) } /* ---------------------------------------------------------------------- - initialize other atom quantities + initialize non-zero atom quantities ------------------------------------------------------------------------- */ void AtomVecTemplate::create_atom_post(int ilocal) diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp index 5450b23293..4fcebc2f84 100644 --- a/src/PERI/atom_vec_peri.cpp +++ b/src/PERI/atom_vec_peri.cpp @@ -70,21 +70,17 @@ AtomVecPeri::AtomVecPeri(LAMMPS *lmp) : AtomVec(lmp) } /* ---------------------------------------------------------------------- - create one atom of itype at coord - modify what default AtomVec::create_atom() just created + initialize non-zero atom quantities ------------------------------------------------------------------------- */ -void AtomVecPeri::create_atom(int itype, double *coord) +void AtomVecPeri::create_atom_post(int ilocal) { - AtomVec::create_atom(itype,coord); - int ilocal = atom->nlocal-1; - atom->vfrac[ilocal] = 1.0; atom->rmass[ilocal] = 1.0; atom->s0[ilocal] = DBL_MAX; - atom->x0[ilocal][0] = coord[0]; - atom->x0[ilocal][1] = coord[1]; - atom->x0[ilocal][2] = coord[2]; + atom->x0[ilocal][0] = atom->x[ilocal][0]; + atom->x0[ilocal][1] = atom->x[ilocal][1]; + atom->x0[ilocal][2] = atom->x[ilocal][2]; } /* ---------------------------------------------------------------------- diff --git a/src/PERI/atom_vec_peri.h b/src/PERI/atom_vec_peri.h index 3b41950a6f..13a62eb194 100644 --- a/src/PERI/atom_vec_peri.h +++ b/src/PERI/atom_vec_peri.h @@ -27,7 +27,7 @@ namespace LAMMPS_NS { class AtomVecPeri : public AtomVec { public: AtomVecPeri(class LAMMPS *); - void create_atom(int, double *); + void create_atom_post(int); void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); diff --git a/src/USER-DPD/atom_vec_dpd.cpp b/src/USER-DPD/atom_vec_dpd.cpp index d1768d473e..27e0f70a20 100644 --- a/src/USER-DPD/atom_vec_dpd.cpp +++ b/src/USER-DPD/atom_vec_dpd.cpp @@ -17,13 +17,7 @@ #include "atom_vec_dpd.h" #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -34,904 +28,55 @@ AtomVecDPD::AtomVecDPD(LAMMPS *lmp) : AtomVec(lmp) molecular = 0; mass_type = 1; - comm_x_only = comm_f_only = 0; // we communicate not only x forward but also dpdTheta - size_forward = 7; // 3 + dpdTheta + uCond + uMech + uChem - size_reverse = 3; // 3 - size_border = 12; // 6 + dpdTheta + uCond + uMech + uChem + uCG + uCGnew - size_velocity = 3; - size_data_atom = 6; // we read id + type + dpdTheta + x + y + z - size_data_vel = 4; - xcol_data = 4; // 1=id 2=type 3=dpdTheta 4=x - atom->rho_flag = 1; atom->dpd_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecDPD::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0) - error->one(FLERR,"Per-processor system is too big"); - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file - rho = memory->grow(atom->rho, nmax, "atom:rho"); - dpdTheta = memory->grow(atom->dpdTheta, nmax, "atom:dpdTheta"); - uCond = memory->grow(atom->uCond,nmax,"atom:uCond"); - uMech = memory->grow(atom->uMech,nmax,"atom:uMech"); - uChem = memory->grow(atom->uChem,nmax,"atom:uChem"); - uCG = memory->grow(atom->uCG,nmax,"atom:uCG"); - uCGnew = memory->grow(atom->uCGnew,nmax,"atom:uCGnew"); - duChem = memory->grow(atom->duChem,nmax,"atom:duChem"); + fields_grow = (char *) "rho dpdTheta uCond uMech uChem uCG uCGnew duChem"; + fields_copy = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; + fields_comm = (char *) "dpdTheta uCond uMech uChem"; + fields_comm_vel = (char *) "dpdTheta uCond uMech uChem"; + fields_reverse = NULL; + fields_border = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; + fields_border_vel = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; + fields_exchange = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; + fields_restart = (char *) "dpdTheta uCond uMech uChem"; + fields_create = (char *) "rho dpdTheta uCond uMech uChem uCG uCGnew duChem"; + fields_data_atom = (char *) "id type dpdTheta x"; + fields_data_vel = (char *) "omega"; - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); + setup_fields(); } /* ---------------------------------------------------------------------- - reset local array ptrs + initialize other atom quantities after AtomVec::unpack_restart() ------------------------------------------------------------------------- */ -void AtomVecDPD::grow_reset() +void AtomVecDPD::unpack_restart_init(int ilocal) { - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - rho = atom->rho; - dpdTheta = atom->dpdTheta; - uCond = atom->uCond; - uMech = atom->uMech; - uChem = atom->uChem; - uCG = atom->uCG; - uCGnew = atom->uCGnew; - duChem = atom->duChem; + atom->uCG[ilocal] = 0.0; + atom->uCGnew[ilocal] = 0.0; } /* ---------------------------------------------------------------------- - copy atom I info to atom J + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecDPD::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - dpdTheta[j] = dpdTheta[i]; - uCond[j] = uCond[i]; - uMech[j] = uMech[i]; - uChem[j] = uChem[i]; - uCG[j] = uCG[i]; - uCGnew[j] = uCGnew[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDPD::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - dpdTheta[i] = buf[m++]; - uCond[i] = buf[m++]; - uMech[i] = buf[m++]; - uChem[i] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDPD::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - dpdTheta[i] = buf[m++]; - uCond[i] = buf[m++]; - uMech[i] = buf[m++]; - uChem[i] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDPD::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - buf[m++] = uCG[j]; - buf[m++] = uCGnew[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - buf[m++] = uCG[j]; - buf[m++] = uCGnew[j]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - buf[m++] = uCG[j]; - buf[m++] = uCGnew[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - buf[m++] = uCG[j]; - buf[m++] = uCGnew[j]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - buf[m++] = uCG[j]; - buf[m++] = uCGnew[j]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = dpdTheta[j]; - buf[m++] = uCond[j]; - buf[m++] = uMech[j]; - buf[m++] = uChem[j]; - buf[m++] = uCG[j]; - buf[m++] = uCGnew[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDPD::unpack_border(int n, int first, double *buf) +void AtomVecDPD::data_atom_post(int ilocal) { - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - dpdTheta[i] = buf[m++]; - uCond[i] = buf[m++]; - uMech[i] = buf[m++]; - uChem[i] = buf[m++]; - uCG[i] = buf[m++]; - uCGnew[i] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecDPD::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - dpdTheta[i] = buf[m++]; - uCond[i] = buf[m++]; - uMech[i] = buf[m++]; - uChem[i] = buf[m++]; - uCG[i] = buf[m++]; - uCGnew[i] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - dpdTheta[i] = buf[m++]; - uCond[i] = buf[m++]; - uMech[i] = buf[m++]; - uChem[i] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - dpdTheta[i] = buf[m++]; - uCond[i] = buf[m++]; - uMech[i] = buf[m++]; - uChem[i] = buf[m++]; - uCG[i] = buf[m++]; - uCGnew[i] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecDPD::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = dpdTheta[i]; - buf[m++] = uCond[i]; - buf[m++] = uMech[i]; - buf[m++] = uChem[i]; - buf[m++] = uCG[i]; - buf[m++] = uCGnew[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecDPD::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - dpdTheta[nlocal] = buf[m++]; - uCond[nlocal] = buf[m++]; - uMech[nlocal] = buf[m++]; - uChem[nlocal] = buf[m++]; - uCG[nlocal] = buf[m++]; - uCGnew[nlocal] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecDPD::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 15 * nlocal; // 11 + dpdTheta + uCond + uMech + uChem - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecDPD::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = dpdTheta[i]; - buf[m++] = uCond[i]; - buf[m++] = uMech[i]; - buf[m++] = uChem[i]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecDPD::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - dpdTheta[nlocal] = buf[m++]; - uCond[nlocal] = buf[m++]; - uMech[nlocal] = buf[m++]; - uChem[nlocal] = buf[m++]; - uCG[nlocal] = 0.0; - uCGnew[nlocal] = 0.0; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecDPD::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - rho[nlocal] = 0.0; - dpdTheta[nlocal] = 0.0; - uCond[nlocal] = 0.0; - uMech[nlocal] = 0.0; - uChem[nlocal] = 0.0; - uCG[nlocal] = 0.0; - uCGnew[nlocal] = 0.0; - duChem[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecDPD::data_atom(double *coord, tagint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - dpdTheta[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - if (dpdTheta[nlocal] <= 0) - error->one(FLERR,"Internal temperature in Atoms section of date file must be > zero"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - rho[nlocal] = 0.0; - uCond[nlocal] = 0.0; - uMech[nlocal] = 0.0; - uChem[nlocal] = 0.0; - uCG[nlocal] = 0.0; - uCGnew[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecDPD::data_atom_hybrid(int nlocal, char **values) -{ - dpdTheta[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecDPD::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = dpdTheta[i]; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecDPD::pack_data_hybrid(int i, double *buf) -{ - buf[0] = dpdTheta[i]; - return 1; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecDPD::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4],buf[i][5], - (int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i, - (int) ubuf(buf[i][8]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecDPD::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e",buf[0]); - return 1; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecDPD::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - if (atom->memcheck("rho")) bytes += memory->usage(rho,nmax); - if (atom->memcheck("dpdTheta")) bytes += memory->usage(dpdTheta,nmax); - if (atom->memcheck("uCond")) bytes += memory->usage(uCond,nmax); - if (atom->memcheck("uMech")) bytes += memory->usage(uMech,nmax); - if (atom->memcheck("uChem")) bytes += memory->usage(uChem,nmax); - if (atom->memcheck("uCG")) bytes += memory->usage(uCG,nmax); - if (atom->memcheck("uCGnew")) bytes += memory->usage(uCGnew,nmax); - if (atom->memcheck("duChem")) bytes += memory->usage(duChem,nmax); + atom->rho[ilocal] = 0.0; + atom->uCond[ilocal] = 0.0; + atom->uMech[ilocal] = 0.0; + atom->uChem[ilocal] = 0.0; + atom->uCG[ilocal] = 0.0; + atom->uCGnew[ilocal] = 0.0; - return bytes; + if (atom->dpdTheta[ilocal] <= 0) + error->one(FLERR,"Internal temperature in Atoms section of date file " + "must be > zero"); } diff --git a/src/USER-DPD/atom_vec_dpd.h b/src/USER-DPD/atom_vec_dpd.h index 234d2ccce7..20c8a9a2d2 100644 --- a/src/USER-DPD/atom_vec_dpd.h +++ b/src/USER-DPD/atom_vec_dpd.h @@ -27,46 +27,8 @@ namespace LAMMPS_NS { class AtomVecDPD : public AtomVec { public: AtomVecDPD(class LAMMPS *); - virtual ~AtomVecDPD() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - bigint memory_usage(); - double *uCond,*uMech,*uChem,*uCG,*uCGnew,*rho,*dpdTheta; - double *duChem; - - protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - + void unpack_restart_init(int); + void data_atom_post(int); }; } @@ -76,15 +38,6 @@ class AtomVecDPD : public AtomVec { /* ERROR/WARNING messages: -E: Per-processor system is too big - -The number of owned atoms plus ghost atoms on a single -processor must fit in 32-bit integer. - -E: Invalid atom type in Atoms section of data file - -Atom types must range from 1 to specified # of types. - E: Internal temperature in Atoms section of data file must be > zero All internal temperatures must be > zero diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp index 552a89c04a..fc73bf4dd5 100644 --- a/src/USER-EFF/atom_vec_electron.cpp +++ b/src/USER-EFF/atom_vec_electron.cpp @@ -46,929 +46,61 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) { if (lmp->citeme) lmp->citeme->add(cite_user_eff_package); - comm_x_only = comm_f_only = 0; - - mass_type = 1; - molecular = 0; forceclearflag = 1; - size_forward = 4; - size_reverse = 4; - size_border = 9; - size_velocity = 3; - size_data_atom = 8; - size_data_vel = 5; - xcol_data = 6; - atom->ecp_flag = 0; atom->electron_flag = 1; atom->q_flag = atom->spin_flag = atom->eradius_flag = atom->ervel_flag = atom->erforce_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom-electron arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecElectron::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - q = memory->grow(atom->q,nmax,"atom:q"); - spin = memory->grow(atom->spin,nmax,"atom:spin"); - eradius = memory->grow(atom->eradius,nmax,"atom:eradius"); - ervel = memory->grow(atom->ervel,nmax,"atom:ervel"); - erforce = memory->grow(atom->erforce,nmax*comm->nthreads,"atom:erforce"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecElectron::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - q = atom->q; - eradius = atom->eradius; ervel = atom->ervel; erforce = atom->erforce; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecElectron::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - q[j] = q[i]; - spin[j] = spin[i]; - eradius[j] = eradius[i]; - ervel[j] = ervel[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecElectron::force_clear(int n, size_t nbytes) -{ - memset(&erforce[n],0,nbytes); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = eradius[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = eradius[j]; - } - } - return m; -} -/* ---------------------------------------------------------------------- */ + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file -int AtomVecElectron::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; + fields_grow = (char *) "q spin eradius ervel erforce"; + fields_copy = (char *) "q spin eradius ervel"; + fields_comm = (char *) "eradius"; + fields_comm_vel = (char *) "eradius"; + fields_reverse = (char *) "erforce"; + fields_border = (char *) "q spin eradius"; + fields_border_vel = (char *) "q spin eradius"; + fields_exchange = (char *) "q spin eradius ervel"; + fields_restart = (char *) "q spin eradius ervel"; + fields_create = (char *) "q spin eradius ervel"; + fields_data_atom = (char *) "id type q spin eradius x"; + fields_data_vel = (char *) "ervel"; - m = 0; - if (pbc_flag == 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]; - buf[m++] = eradius[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = eradius[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = eradius[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - return m; + setup_fields(); } /* ---------------------------------------------------------------------- */ -int AtomVecElectron::pack_comm_hybrid(int n, int *list, double *buf) +void AtomVecElectron::force_clear(int /*n*/, size_t nbytes) { - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = eradius[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecElectron::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - eradius[i] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecElectron::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - eradius[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - eradius[i] = buf[m++]; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = erforce[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - buf[m++] = erforce[i]; - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecElectron::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - erforce[j] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::unpack_reverse_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - erforce[j] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (domain->triclinic == 0) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecElectron::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - spin[i] = (int) ubuf(buf[m++]).i; - eradius[i] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecElectron::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - spin[i] = (int) ubuf(buf[m++]).i; - eradius[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - q[i] = buf[m++]; - spin[i] = (int) ubuf(buf[m++]).i; - eradius[i] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecElectron::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = q[i]; - buf[m++] = ubuf(spin[i]).d; - buf[m++] = eradius[i]; - buf[m++] = ervel[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecElectron::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - q[nlocal] = buf[m++]; - spin[nlocal] = (int) ubuf(buf[m++]).i; - eradius[nlocal] = buf[m++]; - ervel[nlocal] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecElectron::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 15 * nlocal; // Associated with pack_restart - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecElectron::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = q[i]; - buf[m++] = ubuf(spin[i]).d; - buf[m++] = eradius[i]; - buf[m++] = ervel[i]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecElectron::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - q[nlocal] = buf[m++]; - spin[nlocal] = (int) ubuf(buf[m++]).i; - eradius[nlocal] = buf[m++]; - ervel[nlocal] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecElectron::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - q[nlocal] = 0.0; - spin[nlocal] = 1; - eradius[nlocal] = 1.0; - ervel[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecElectron::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - q[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - spin[nlocal] = utils::inumeric(FLERR,values[3],true,lmp); - if (spin[nlocal] == 3) atom->ecp_flag = 1; - - eradius[nlocal] = utils::numeric(FLERR,values[4],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - ervel[nlocal] = 0.0; - - atom->nlocal++; + memset(&atom->erforce[0],0,nbytes); } /* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style + initialize non-zero atom quantities ------------------------------------------------------------------------- */ -int AtomVecElectron::data_atom_hybrid(int nlocal, char **values) +void AtomVecElectron::create_atom_post(int ilocal) { - q[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - spin[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - eradius[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - if (eradius[nlocal] < 0.0) - error->one(FLERR,"Invalid eradius in Atoms section of data file"); - - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - ervel[nlocal] = 0.0; - - return 3; + atom->spin[ilocal] = 1; + atom->eradius[ilocal] = 1.0; } /* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecElectron::data_vel(int m, char **values) +void AtomVecElectron::data_atom_post(int ilocal) { - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - ervel[m] = utils::numeric(FLERR,values[3],true,lmp); -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file -------------------------------------------------------------------------- */ - -int AtomVecElectron::data_vel_hybrid(int m, char **values) -{ - ervel[m] = utils::numeric(FLERR,values[0],true,lmp); - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecElectron::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = q[i]; - buf[i][3] = ubuf(spin[i]).d; - buf[i][4] = eradius[i]; - buf[i][5] = x[i][0]; - buf[i][6] = x[i][1]; - buf[i][7] = x[i][2]; - buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecElectron::pack_data_hybrid(int i, double *buf) -{ - buf[0] = q[i]; - buf[1] = ubuf(spin[i]).d; - buf[2] = eradius[i]; - return 3; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecElectron::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %-1.16e %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i,buf[i][2], - (int) ubuf(buf[i][3]).i,buf[i][4],buf[i][5],buf[i][6],buf[i][7], - (int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i, - (int) ubuf(buf[i][10]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecElectron::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %d %-1.16e",buf[0],(int) ubuf(buf[1]).i,buf[2]); - return 3; -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ - -void AtomVecElectron::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = ervel[i]; - } -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ - -int AtomVecElectron::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = ervel[i]; - return 1; -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file -------------------------------------------------------------------------- */ - -void AtomVecElectron::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],buf[i][4]); -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file -------------------------------------------------------------------------- */ - -int AtomVecElectron::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e",buf[0]); - return 1; + atom->ervel[ilocal] = 0.0; + if (atom->spin[ilocal] == 3) atom->ecp_flag = 1; } /* ---------------------------------------------------------------------- @@ -998,24 +130,28 @@ void AtomVecElectron::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { + int *spin = atom->spin; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = spin[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 1) { + double *eradius = atom->eradius; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = eradius[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 2) { + double *ervel = atom->ervel; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = ervel[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 3) { + double *erforce = atom->erforce; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = erforce[i]; else buf[n] = 0.0; @@ -1023,29 +159,3 @@ void AtomVecElectron::pack_property_atom(int index, double *buf, } } } - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecElectron::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("q")) bytes += memory->usage(q,nmax); - if (atom->memcheck("spin")) bytes += memory->usage(spin,nmax); - if (atom->memcheck("eradius")) bytes += memory->usage(eradius,nmax); - if (atom->memcheck("ervel")) bytes += memory->usage(ervel,nmax); - if (atom->memcheck("erforce")) - bytes += memory->usage(erforce,nmax*comm->nthreads); - - return bytes; -} diff --git a/src/USER-EFF/atom_vec_electron.h b/src/USER-EFF/atom_vec_electron.h index 6e79775c3d..fabb03438d 100644 --- a/src/USER-EFF/atom_vec_electron.h +++ b/src/USER-EFF/atom_vec_electron.h @@ -27,56 +27,11 @@ namespace LAMMPS_NS { class AtomVecElectron : public AtomVec { public: AtomVecElectron(class LAMMPS *); - ~AtomVecElectron() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); void force_clear(int, size_t); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); + void create_atom_post(int); + void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); - bigint memory_usage(); - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - int *spin; - double *q,*eradius,*ervel,*erforce; }; } diff --git a/src/USER-MESO/atom_vec_edpd.cpp b/src/USER-MESO/atom_vec_edpd.cpp index edc7a34331..59cee397b5 100644 --- a/src/USER-MESO/atom_vec_edpd.cpp +++ b/src/USER-MESO/atom_vec_edpd.cpp @@ -10,6 +10,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ + #include "atom_vec_edpd.h" #include #include "atom.h" @@ -28,817 +29,65 @@ using namespace LAMMPS_NS; AtomVecEDPD::AtomVecEDPD(LAMMPS *lmp) : AtomVec(lmp) { - if(strcmp(update->unit_style,"lj") != 0) + if (strcmp(update->unit_style,"lj") != 0) error->all(FLERR,"Atom style edpd requires lj units"); molecular = 0; mass_type = 1; forceclearflag = 1; - comm_x_only = comm_f_only = 0; - comm->ghost_velocity = 1; - - size_forward = 3 + 5; // edpd_temp + vest[4] - size_reverse = 3 + 1; // edpd_flux - size_border = 6 + 6; // edpd_temp + edpd_cv + vest[4] - size_velocity = 3; - size_data_atom = 5 + 2; // we read id + type + edpd_temp + edpd_cv + xyz[3] - size_data_vel = 4; - xcol_data = 5; - atom->edpd_flag = 1; atom->vest_flag = 1; -} -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file -void AtomVecEDPD::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - edpd_cv= memory->grow(atom->edpd_cv, nmax, "atom:edpd_cv"); - edpd_temp = memory->grow(atom->edpd_temp, nmax, "atom:edpd_temp"); - edpd_flux = memory->grow(atom->edpd_flux, nmax*comm->nthreads,"atom:edpd_flux"); - vest = memory->grow(atom->vest, nmax, 4, "atom:vest"); + fields_grow = (char *) "edpd_cv edpd_temp edpd_flux vest"; + fields_copy = (char *) "edpd_cv edpd_temp edpd_flux vest"; + fields_comm = (char *) "edpd_temp vest"; + fields_comm_vel = (char *) "edpd_temp vest"; + fields_reverse = (char *) "edpd_flux"; + fields_border = (char *) "edpd_cv edpd_temp vest"; + fields_border_vel = (char *) "edpd_cv edpd_temp vest"; + fields_exchange = (char *) "edpd_cv edpd_temp vest"; + fields_restart = (char * ) "edpd_cv edpd_temp vest"; + fields_create = (char *) "edpd_cv edpd_temp edpd_flux vest"; + fields_data_atom = (char *) "id type edpd_temp edpd_cv x"; + fields_data_vel = NULL; - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecEDPD::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - edpd_cv = atom->cv; edpd_temp = atom->edpd_temp; edpd_flux = atom->edpd_flux; - vest = atom->vest; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecEDPD::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - edpd_temp[j] = edpd_temp[i]; - edpd_flux[j] = edpd_flux[i]; - edpd_cv[j] = edpd_cv[i]; - vest[j][0] = vest[i][0]; - vest[j][1] = vest[i][1]; - vest[j][2] = vest[i][2]; - vest[j][3] = vest[i][3]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - - -void AtomVecEDPD::force_clear(int n, size_t nbytes) -{ - memset(&edpd_flux[n],0,nbytes); -} - - -/* ---------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = edpd_temp[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = edpd_temp[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = edpd_temp[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = edpd_temp[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = edpd_temp[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } - } - return m; + setup_fields(); } /* ---------------------------------------------------------------------- */ -void AtomVecEDPD::unpack_comm(int n, int first, double *buf) +void AtomVecEDPD::force_clear(int /*n*/, size_t nbytes) { - int i,m,last; - - 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++]; - edpd_temp[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - vest[i][3] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEDPD::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - edpd_temp[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - vest[i][3] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = edpd_flux[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEDPD::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - edpd_flux[j] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = edpd_temp[j]; - buf[m++] = edpd_cv[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = edpd_temp[j]; - buf[m++] = edpd_cv[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = edpd_temp[j]; - buf[m++] = edpd_cv[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = edpd_temp[j]; - buf[m++] = edpd_cv[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = edpd_temp[j]; - buf[m++] = edpd_cv[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - buf[m++] = vest[j][0] + dvx; - buf[m++] = vest[j][1] + dvy; - buf[m++] = vest[j][2] + dvz; - buf[m++] = vest[j][3]; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = vest[j][3]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEDPD::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - edpd_temp[i] = buf[m++]; - edpd_cv[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - vest[i][3] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEDPD::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - edpd_temp[i] = buf[m++]; - edpd_cv[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - vest[i][3] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = edpd_temp[i]; - buf[m++] = edpd_cv[i]; - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - buf[m++] = vest[i][3]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEDPD::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - edpd_temp[nlocal] = buf[m++]; - edpd_cv[nlocal] = buf[m++]; - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - vest[nlocal][3] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecEDPD::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = (11 + 6) * nlocal; // 11 + edpd_temp + edpd_cv + vest[4] - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecEDPD::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = edpd_temp[i]; - buf[m++] = edpd_cv[i]; - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - buf[m++] = vest[i][3]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; + memset(&atom->edpd_flux[0],0,nbytes); } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities + initialize non-zero atom quantities ------------------------------------------------------------------------- */ -int AtomVecEDPD::unpack_restart(double *buf) +void AtomVecEDPD::create_atom_post(int ilocal) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - edpd_temp[nlocal] = buf[m++]; - edpd_cv[nlocal]= buf[m++]; - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - vest[nlocal][3] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecEDPD::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - edpd_temp[nlocal] = 1.0; - edpd_flux[nlocal] = 0.0; - edpd_cv[nlocal]= 1.0E5; - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - vest[nlocal][3] = edpd_temp[nlocal]; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecEDPD::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - edpd_temp[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - edpd_cv[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - vest[nlocal][3] = edpd_temp[nlocal]; - edpd_flux[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecEDPD::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = edpd_temp[i]; - buf[i][3] = edpd_cv[i]; - buf[i][4] = x[i][0]; - buf[i][5] = x[i][1]; - buf[i][6] = x[i][2]; - buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecEDPD::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4],buf[i][5],buf[i][6], - (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i); + atom->edpd_temp[ilocal] = 1.0; + atom->edpd_cv[ilocal]= 1.0e5; + atom->vest[ilocal][3] = atom->edpd_temp[ilocal]; } /* ---------------------------------------------------------------------- - return # of bytes of allocated memory + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -bigint AtomVecEDPD::memory_usage() +void AtomVecEDPD::data_atom_post(int ilocal) { - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - if (atom->memcheck("edpd_temp")) bytes += memory->usage(edpd_temp,nmax); - if (atom->memcheck("edpd_flux")) bytes += memory->usage(edpd_flux,nmax*comm->nthreads); - if (atom->memcheck("edpd_cv")) bytes += memory->usage(edpd_cv,nmax); - if (atom->memcheck("vest")) bytes += memory->usage(vest,nmax,4); - - return bytes; + atom->edpd_flux[ilocal] = 0.0; + atom->vest[ilocal][0] = 0.0; + atom->vest[ilocal][1] = 0.0; + atom->vest[ilocal][2] = 0.0; + atom->vest[ilocal][3] = atom->edpd_temp[ilocal]; } diff --git a/src/USER-MESO/atom_vec_edpd.h b/src/USER-MESO/atom_vec_edpd.h index 36a4cae97b..7d41b51665 100644 --- a/src/USER-MESO/atom_vec_edpd.h +++ b/src/USER-MESO/atom_vec_edpd.h @@ -27,39 +27,9 @@ namespace LAMMPS_NS { class AtomVecEDPD : public AtomVec { public: AtomVecEDPD(class LAMMPS *); - virtual ~AtomVecEDPD() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); void force_clear(int, size_t); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - void pack_data(double **); - void write_data(FILE *, int, double **); - bigint memory_usage(); - - protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double **vest; // store intermediate velocity for using mvv integrator - double *edpd_temp,*edpd_flux,*edpd_cv; // temperature, heat flux, and heat capacity + void create_atom_post(int); + void data_atom_post(int); }; } diff --git a/src/atom.cpp b/src/atom.cpp index e1736e321c..d238db5e65 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -459,8 +459,8 @@ void Atom::peratom_create() add_peratom("radius",&radius,DOUBLE,0); add_peratom("omega",&omega,DOUBLE,3); - add_peratom("amgmom",&angmom,DOUBLE,3); add_peratom("torque",&torque,DOUBLE,3,1); // set per-thread flag + add_peratom("angmom",&angmom,DOUBLE,3); add_peratom("ellipsoid",&ellipsoid,INT,0); add_peratom("line",&line,INT,0); @@ -524,6 +524,31 @@ void Atom::peratom_create() add_peratom("sp",&sp,DOUBLE,4); add_peratom("fm",&fm,DOUBLE,3,1); add_peratom("fm_long",&fm_long,DOUBLE,3,1); + + // USER-EFF package + + add_peratom("spin",&spin,INT,0); + add_peratom("eradius",&eradius,DOUBLE,0); + add_peratom("ervel",&ervel,DOUBLE,0); + add_peratom("erforce",&erforce,DOUBLE,0,1); // set per-thread flag + + // USER-DPD package + + add_peratom("rho",&eradius,DOUBLE,0); + add_peratom("dpdTheta",&dpdTheta,DOUBLE,0); + add_peratom("uCond",&uCond,DOUBLE,0); + add_peratom("uMech",&uMech,DOUBLE,0); + add_peratom("uChem",&uChem,DOUBLE,0); + add_peratom("uCG",&uCG,DOUBLE,0); + add_peratom("uCGnew",&uCGnew,DOUBLE,0); + add_peratom("duChem",&duChem,DOUBLE,0); + + // USER-MESO package + + add_peratom("edpd_cv",&edpd_cv,DOUBLE,0); + add_peratom("edpd_temp",&edpd_temp,DOUBLE,0); + add_peratom("edpd_flux",&edpd_flux,DOUBLE,0,1); // set per-thread flag + add_peratom("vest",&vest,DOUBLE,4); } /* ---------------------------------------------------------------------- @@ -1605,8 +1630,7 @@ void Atom::data_bonus(int n, char *buf, AtomVec *avec_bonus, tagint id_offset) call style-specific routine to parse line ------------------------------------------------------------------------- */ -void Atom::data_bodies(int n, char *buf, AtomVecBody *avec_body, - tagint id_offset) +void Atom::data_bodies(int n, char *buf, AtomVec *avec_body, tagint id_offset) { int j,m,nvalues,tagdata,ninteger,ndouble; diff --git a/src/atom.h b/src/atom.h index 6cc5dff72a..a105b3e5b1 100644 --- a/src/atom.h +++ b/src/atom.h @@ -121,7 +121,7 @@ class Atom : protected Pointers { // USER-MESO package - double **cc, **cc_flux; // cc = chemical concentration + double **cc,**cc_flux; // cc = chemical concentration double *edpd_temp,*edpd_flux; // temperature and heat flux double *edpd_cv; // heat capacity int cc_species; @@ -141,13 +141,12 @@ class Atom : protected Pointers { double **vest; // -------------------------------------------------------------------- - // 1st customization section: customize by adding new flag - // existence flags for per-atom vectors and arrays + // 1st customization section: customize by adding new flags + // most are existence flags for per-atom vectors and arrays // 1 if variable is used, 0 if not int sphere_flag,ellipsoid_flag,line_flag,tri_flag,body_flag; int peri_flag,electron_flag; - int ecp_flag; int wavepacket_flag,sph_flag; int molecule_flag,molindex_flag,molatom_flag; @@ -158,10 +157,14 @@ class Atom : protected Pointers { int rho_flag,e_flag,cv_flag,vest_flag; int dpd_flag,edpd_flag,tdpd_flag; - // USER-SPIN package + // SPIN package int sp_flag; + // USER-EFF package + + int ecp_flag; + // USER-SMD package int smd_flag; @@ -286,7 +289,7 @@ class Atom : protected Pointers { void data_dihedrals(int, char *, int *, tagint, int); void data_impropers(int, char *, int *, tagint, int); void data_bonus(int, char *, class AtomVec *, tagint); - void data_bodies(int, char *, class AtomVecBody *, tagint); + void data_bodies(int, char *, class AtomVec *, tagint); void data_fix_compute_variable(int, int); virtual void allocate_type_arrays(); diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index 776d7a4619..ed56151d33 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -38,11 +38,13 @@ enum{DOUBLE,INT,BIGINT}; AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp) { nmax = 0; + + molecular = 0; bonds_allow = angles_allow = dihedrals_allow = impropers_allow = 0; mass_type = dipole_type = 0; forceclearflag = 0; - size_data_bonus = 0; maxexchange = 0; + bonus_flag = 0; kokkosable = 0; @@ -309,6 +311,8 @@ void AtomVec::copy(int i, int j, int delflag) } } + if (bonus_flag) copy_bonus(i,j,delflag); + if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); @@ -349,7 +353,7 @@ int AtomVec::pack_comm(int n, int *list, double *buf, } } - if (comm) { + if (ncomm) { for (nn = 0; nn < ncomm; nn++) { pdata = mcomm.pdata[nn]; datatype = mcomm.datatype[nn]; @@ -403,6 +407,8 @@ int AtomVec::pack_comm(int n, int *list, double *buf, } } + if (bonus_flag) m += pack_comm_bonus(n,list,&buf[m]); + return m; } @@ -522,6 +528,8 @@ int AtomVec::pack_comm_vel(int n, int *list, double *buf, } } + if (bonus_flag) m += pack_comm_bonus(n,list,&buf[m]); + return m; } @@ -581,6 +589,8 @@ void AtomVec::unpack_comm(int n, int first, double *buf) } } } + + if (bonus_flag) unpack_comm_bonus(n,first,&buf[m]); } /* ---------------------------------------------------------------------- */ @@ -642,6 +652,8 @@ void AtomVec::unpack_comm_vel(int n, int first, double *buf) } } } + + if (bonus_flag) unpack_comm_bonus(n,first,&buf[m]); } /* ---------------------------------------------------------------------- */ @@ -874,6 +886,8 @@ int AtomVec::pack_border(int n, int *list, double *buf, int pbc_flag, int *pbc) } } + if (bonus_flag) m += pack_border_bonus(n,list,&buf[m]); + if (atom->nextra_border) for (int iextra = 0; iextra < atom->nextra_border; iextra++) m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); @@ -1006,6 +1020,8 @@ int AtomVec::pack_border_vel(int n, int *list, double *buf, } } + if (bonus_flag) m += pack_border_bonus(n,list,&buf[m]); + if (atom->nextra_border) for (int iextra = 0; iextra < atom->nextra_border; iextra++) m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); @@ -1074,6 +1090,8 @@ void AtomVec::unpack_border(int n, int first, double *buf) } } + if (bonus_flag) m += unpack_border_bonus(n,first,&buf[m]); + if (atom->nextra_border) for (int iextra = 0; iextra < atom->nextra_border; iextra++) m += modify->fix[atom->extra_border[iextra]]-> @@ -1144,6 +1162,8 @@ void AtomVec::unpack_border_vel(int n, int first, double *buf) } } + if (bonus_flag) m += unpack_border_bonus(n,first,&buf[m]); + if (atom->nextra_border) for (int iextra = 0; iextra < atom->nextra_border; iextra++) m += modify->fix[atom->extra_border[iextra]]-> @@ -1232,6 +1252,8 @@ int AtomVec::pack_exchange(int i, double *buf) } } + if (bonus_flag) m += pack_exchange_bonus(i,&buf[m]); + if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); @@ -1322,6 +1344,8 @@ int AtomVec::unpack_exchange(double *buf) } } + if (bonus_flag) m += unpack_exchange_bonus(nlocal,&buf[m]); + if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) m += modify->fix[atom->extra_grow[iextra]]-> @@ -1366,6 +1390,8 @@ int AtomVec::size_restart() } } + if (bonus_flag) n += size_restart_bonus(); + if (atom->nextra_restart) for (int iextra = 0; iextra < atom->nextra_restart; iextra++) for (i = 0; i < nlocal; i++) @@ -1459,6 +1485,8 @@ int AtomVec::pack_restart(int i, double *buf) } } + if (bonus_flag) m += pack_restart_bonus(i,&buf[m]); + // if needed, restore values after packing pack_restart_post(i); @@ -1558,6 +1586,8 @@ int AtomVec::unpack_restart(double *buf) } } + if (bonus_flag) m += unpack_restart_bonus(nlocal,&buf[m]); + // if needed, initialize other peratom values unpack_restart_init(nlocal); @@ -1635,7 +1665,7 @@ void AtomVec::create_atom(int itype, double *coord) } } - // if needed, initialize other peratom values + // if needed, initialize non-zero peratom values create_atom_post(nlocal); @@ -2295,6 +2325,8 @@ bigint AtomVec::memory_usage() } } + if (bonus_flag) bytes += memory_usage_bonus(); + return bytes; } @@ -2359,8 +2391,9 @@ void AtomVec::setup_fields() // NOTE: check for others vars in atom_vec.cpp/h ?? // NOTE: need to set maxexchange, e.g for style hybrid? - if (ncomm == 0) comm_x_only = 1; - else comm_x_only = 0; + comm_x_only = 1; + if (ncomm) comm_x_only = 0; + if (bonus_flag && size_forward_bonus) comm_x_only = 0; if (nreverse == 0) comm_f_only = 1; else comm_f_only = 0; @@ -2371,6 +2404,7 @@ void AtomVec::setup_fields() if (cols == 0) size_forward++; else size_forward += cols; } + if (bonus_flag) size_forward += size_forward_bonus; size_reverse = 3; for (n = 0; n < nreverse; n++) { @@ -2385,6 +2419,7 @@ void AtomVec::setup_fields() if (cols == 0) size_border++; else size_border += cols; } + if (bonus_flag) size_border += size_border_bonus; size_velocity = 3; for (n = 0; n < ncomm_vel; n++) { @@ -2444,7 +2479,10 @@ int AtomVec::process_fields(char *list, const char *default_list, Method *method for (i = 0; i < nperatom; i++) if (strcmp(field,peratom[i].name) == 0) break; - if (i == nperatom) error->all(FLERR,"Atom_style unrecognized peratom field"); + if (i == nperatom) { + printf("FIELD %s\n",field); + error->all(FLERR,"Atom_style unrecognized peratom field"); + } index[nfield++] = i; // error if field is in default list or appears multiple times diff --git a/src/atom_vec.h b/src/atom_vec.h index 8ed6fff35f..33bf4a3ccd 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -36,11 +36,16 @@ class AtomVec : protected Pointers { int size_velocity; // # of velocity based quantities int size_data_atom; // number of values in Atom line int size_data_vel; // number of values in Velocity line - int size_data_bonus; // number of values in Bonus line int xcol_data; // column (1-N) where x is in Atom line int maxexchange; // max size of exchanged atom // only needs to be set if size > BUFEXTRA + int bonus_flag; // 1 if stores bonus data + int size_forward_bonus; // # in forward bonus comm + int size_border_bonus; // # in border bonus comm + int size_restart_bonus_one; // # in restart bonus comm + int size_data_bonus; // number of values in Bonus line + class Molecule **onemols; // list of molecules for style template int nset; // # of molecules in list @@ -62,6 +67,7 @@ class AtomVec : protected Pointers { AtomVec(class LAMMPS *); virtual ~AtomVec(); + void store_args(int, char **); virtual void process_args(int, char **); virtual void init(); @@ -70,13 +76,18 @@ class AtomVec : protected Pointers { void grow(int); void copy(int, int, int); - void clear_bonus() {} + + virtual void copy_bonus(int, int, int) {} + virtual void clear_bonus() {} int pack_comm(int, int *, double *, int, int *); int pack_comm_vel(int, int *, double *, int, int *); void unpack_comm(int, int, double *); void unpack_comm_vel(int, int, double *); + virtual int pack_comm_bonus(int, int *, double *) {} + virtual void unpack_comm_bonus(int, int, double *) {} + int pack_reverse(int, int, double *); void unpack_reverse(int, int *, double *); @@ -85,16 +96,27 @@ class AtomVec : protected Pointers { void unpack_border(int, int, double *); void unpack_border_vel(int, int, double *); + virtual int pack_border_bonus(int, int *, double *) {} + virtual int unpack_border_bonus(int, int, double *) {} + int pack_exchange(int, double *); int unpack_exchange(double *); + virtual int pack_exchange_bonus(int, double *) {} + virtual int unpack_exchange_bonus(int, double *) {} + int size_restart(); - virtual void pack_restart_pre(int) {} int pack_restart(int, double *); - virtual void pack_restart_post(int) {} int unpack_restart(double *); + + virtual void pack_restart_pre(int) {} + virtual void pack_restart_post(int) {} virtual void unpack_restart_init(int) {} + virtual int size_restart_bonus() {} + virtual int pack_restart_bonus(int, double *) {} + virtual int unpack_restart_bonus(int, double *) {} + void create_atom(int, double *); virtual void create_atom_post(int) {} @@ -102,13 +124,15 @@ class AtomVec : protected Pointers { virtual void data_atom_post(int) {} void data_atom_bonus(int, char **) {} - void data_vel(int, char **); + void data_body(int, int, int, int *, double *) {} - virtual void pack_data_pre(int) {} void pack_data(double **); - virtual void pack_data_post(int) {} - int pack_data_hybrid(int, double *) {return 0;} void write_data(FILE *, int, double **); + + virtual void pack_data_pre(int) {} + virtual void pack_data_post(int) {} + + void data_vel(int, char **); void pack_vel(double **); void write_vel(FILE *, int, double **); @@ -125,6 +149,7 @@ class AtomVec : protected Pointers { void pack_property_atom(int, double *, int, int) {} bigint memory_usage(); + virtual bigint memory_usage_bonus() {} protected: int nmax; // local copy of atom->nmax diff --git a/src/atom_vec_body.cpp b/src/atom_vec_body.cpp index 5e83946078..1a8c2defd9 100644 --- a/src/atom_vec_body.cpp +++ b/src/atom_vec_body.cpp @@ -18,7 +18,6 @@ #include "style_body.h" #include "body.h" #include "atom.h" -#include "comm.h" #include "domain.h" #include "modify.h" #include "fix.h" @@ -33,17 +32,17 @@ using namespace LAMMPS_NS; AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp) { molecular = 0; + bonus_flag = 1; - // size_forward and size_border set in settings(), via Body class + // first 3 sizes do not include values from body itself + // 1st,2nd body counts are added in process_args() via body style + // 3rd body count is added in size_restart_bonus() + // size_data_bonus is not used by Atom class for body style - comm_x_only = comm_f_only = 0; - size_forward = 0; - size_reverse = 6; - size_border = 0; - size_velocity = 6; - size_data_atom = 7; - size_data_vel = 7; - xcol_data = 5; + size_forward_bonus = 4; + size_border_bonus = 9; + size_restart_bonus_one = 9; + size_data_bonus = 0; atom->body_flag = 1; atom->rmass_flag = 1; @@ -58,6 +57,26 @@ AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp) if (sizeof(double) == sizeof(int)) intdoubleratio = 1; else if (sizeof(double) == 2*sizeof(int)) intdoubleratio = 2; else error->all(FLERR,"Internal error in atom_style body"); + + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) "radius rmass angmom torque body"; + fields_copy = (char *) "radius rmass angmom"; + fields_comm = NULL; + fields_comm_vel = (char *) "angmom"; + fields_reverse = (char *) "torque"; + fields_border = (char *) "radius rmass"; + fields_border_vel = (char *) "radius rmass angmom"; + fields_exchange = (char *) "radius rmass angmom"; + fields_restart = (char *) "radius rmass angmom"; + fields_create = (char *) "radius rmass angmom tri"; + fields_data_atom = (char *) "id type body rmass x"; + fields_data_vel = (char *) "angmom"; + + setup_fields(); } /* ---------------------------------------------------------------------- */ @@ -96,65 +115,18 @@ void AtomVecBody::process_args(int narg, char **arg) #undef BodyStyle #undef BODY_CLASS - else error->all(FLERR,utils::check_packages_for_style("body",arg[0],lmp).c_str()); + else error->all(FLERR,utils:: + check_packages_for_style("body",arg[0],lmp).c_str()); bptr->avec = this; icp = bptr->icp; dcp = bptr->dcp; // max size of forward/border comm - // 7,16 are packed in pack_comm/pack_border // bptr values = max number of additional ivalues/dvalues from Body class - size_forward = 7 + bptr->size_forward; - size_border = 18 + bptr->size_border; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecBody::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - radius = memory->grow(atom->radius,nmax,"atom:radius"); - rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); - angmom = memory->grow(atom->angmom,nmax,3,"atom:angmom"); - torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque"); - body = memory->grow(atom->body,nmax,"atom:body"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecBody::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - radius = atom->radius; rmass = atom->rmass; - angmom = atom->angmom; torque = atom->torque; - body = atom->body; + size_forward_bonus += bptr->size_forward; + size_border_bonus += bptr->size_border; } /* ---------------------------------------------------------------------- @@ -176,24 +148,9 @@ void AtomVecBody::grow_bonus() if delflag and atom J has bonus data, then delete it ------------------------------------------------------------------------- */ -void AtomVecBody::copy(int i, int j, int delflag) +void AtomVecBody::copy_bonus(int i, int j, int delflag) { - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - radius[j] = radius[i]; - rmass[j] = rmass[i]; - angmom[j][0] = angmom[i][0]; - angmom[j][1] = angmom[i][1]; - angmom[j][2] = angmom[i][2]; + int *body = atom->body; // if deleting atom J via delflag and J has bonus data, then delete it @@ -201,7 +158,7 @@ void AtomVecBody::copy(int i, int j, int delflag) int k = body[j]; icp->put(bonus[k].iindex); dcp->put(bonus[k].dindex); - copy_bonus(nlocal_bonus-1,k); + copy_bonus_all(nlocal_bonus-1,k); nlocal_bonus--; } @@ -210,10 +167,6 @@ void AtomVecBody::copy(int i, int j, int delflag) if (body[i] >= 0 && i != j) bonus[body[i]].ilocal = j; body[j] = body[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); } /* ---------------------------------------------------------------------- @@ -221,9 +174,9 @@ void AtomVecBody::copy(int i, int j, int delflag) also reset body that points to I to now point to J ------------------------------------------------------------------------- */ -void AtomVecBody::copy_bonus(int i, int j) +void AtomVecBody::copy_bonus_all(int i, int j) { - body[bonus[i].ilocal] = j; + atom->body[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -240,166 +193,20 @@ void AtomVecBody::clear_bonus() dcp->put(bonus[i].dindex); } nghost_bonus = 0; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - double *quat; - - m = 0; - if (pbc_flag == 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]; - if (body[j] >= 0) { - quat = bonus[body[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]); - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (body[j] >= 0) { - quat = bonus[body[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]); - } - } - } - return m; + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->clear_bonus(); } /* ---------------------------------------------------------------------- */ -int AtomVecBody::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) +int AtomVecBody::pack_comm_bonus(int n, int *list, double *buf) { int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; double *quat; - m = 0; - if (pbc_flag == 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]; - if (body[j] >= 0) { - quat = bonus[body[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]); - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (body[j] >= 0) { - quat = bonus[body[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]); - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (body[j] >= 0) { - quat = bonus[body[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]); - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - double *quat; + int *body = atom->body; m = 0; for (i = 0; i < n; i++) { @@ -413,73 +220,22 @@ int AtomVecBody::pack_comm_hybrid(int n, int *list, double *buf) m += bptr->pack_comm_body(&bonus[body[j]],&buf[m]); } } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecBody::unpack_comm(int n, int first, double *buf) +void AtomVecBody::unpack_comm_bonus(int n, int first, double *buf) { int i,m,last; double *quat; - 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++]; - if (body[i] >= 0) { - quat = bonus[body[i]].quat; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - m += bptr->unpack_comm_body(&bonus[body[i]],&buf[m]); - } - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBody::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - double *quat; + int *body = atom->body; 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++]; - if (body[i] >= 0) { - quat = bonus[body[i]].quat; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - m += bptr->unpack_comm_body(&bonus[body[i]],&buf[m]); - } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - double *quat; - - m = 0; - last = first + n; - for (i = first; i < last; i++) if (body[i] >= 0) { quat = bonus[body[i]].quat; quat[0] = buf[m++]; @@ -488,313 +244,21 @@ int AtomVecBody::unpack_comm_hybrid(int n, int first, double *buf) quat[3] = buf[m++]; m += bptr->unpack_comm_body(&bonus[body[i]],&buf[m]); } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; } - return m; } /* ---------------------------------------------------------------------- */ -int AtomVecBody::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBody::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::unpack_reverse_hybrid(int n, int *list, double *buf) +int AtomVecBody::pack_border_bonus(int n, int *list, double *buf) { int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - double *quat,*inertia; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (body[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[body[j]].quat; - inertia = bonus[body[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - buf[m++] = ubuf(bonus[body[j]].ninteger).d; - buf[m++] = ubuf(bonus[body[j]].ndouble).d; - m += bptr->pack_border_body(&bonus[body[j]],&buf[m]); - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (body[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[body[j]].quat; - inertia = bonus[body[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - buf[m++] = ubuf(bonus[body[j]].ninteger).d; - buf[m++] = ubuf(bonus[body[j]].ndouble).d; - m += bptr->pack_border_body(&bonus[body[j]],&buf[m]); - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; double *quat,*inertia; - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (body[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[body[j]].quat; - inertia = bonus[body[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - buf[m++] = ubuf(bonus[body[j]].ninteger).d; - buf[m++] = ubuf(bonus[body[j]].ndouble).d; - m += bptr->pack_border_body(&bonus[body[j]],&buf[m]); - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (body[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[body[j]].quat; - inertia = bonus[body[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - buf[m++] = ubuf(bonus[body[j]].ninteger).d; - buf[m++] = ubuf(bonus[body[j]].ndouble).d; - m += bptr->pack_border_body(&bonus[body[j]],&buf[m]); - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (body[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[body[j]].quat; - inertia = bonus[body[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - buf[m++] = ubuf(bonus[body[j]].ninteger).d; - buf[m++] = ubuf(bonus[body[j]].ndouble).d; - m += bptr->pack_border_body(&bonus[body[j]],&buf[m]); - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - double *quat,*inertia; + int *body = atom->body; m = 0; for (i = 0; i < n; i++) { j = list[i]; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; if (body[j] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -811,80 +275,23 @@ int AtomVecBody::pack_border_hybrid(int n, int *list, double *buf) buf[m++] = ubuf(bonus[body[j]].ndouble).d; m += bptr->pack_border_body(&bonus[body[j]],&buf[m]); } - } + } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecBody::unpack_border(int n, int first, double *buf) +int AtomVecBody::unpack_border_bonus(int n, int first, double *buf) { int i,j,m,last; double *quat,*inertia; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - body[i] = (int) ubuf(buf[m++]).i; - if (body[i] == 0) body[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - quat = bonus[j].quat; - inertia = bonus[j].inertia; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - inertia[0] = buf[m++]; - inertia[1] = buf[m++]; - inertia[2] = buf[m++]; - bonus[j].ninteger = (int) ubuf(buf[m++]).i; - bonus[j].ndouble = (int) ubuf(buf[m++]).i; - // corresponding put() calls are in clear_bonus() - bonus[j].ivalue = icp->get(bonus[j].ninteger,bonus[j].iindex); - bonus[j].dvalue = dcp->get(bonus[j].ndouble,bonus[j].dindex); - m += bptr->unpack_border_body(&bonus[j],&buf[m]); - bonus[j].ilocal = i; - body[i] = j; - nghost_bonus++; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecBody::unpack_border_vel(int n, int first, double *buf) -{ - int i,j,m,last; - double *quat,*inertia; + int *body = atom->body; m = 0; last = first + n; for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; body[i] = (int) ubuf(buf[m++]).i; if (body[i] == 0) body[i] = -1; else { @@ -909,57 +316,8 @@ void AtomVecBody::unpack_border_vel(int n, int first, double *buf) body[i] = j; nghost_bonus++; } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; } - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecBody::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,j,m,last; - double *quat,*inertia; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - body[i] = (int) ubuf(buf[m++]).i; - if (body[i] == 0) body[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - quat = bonus[j].quat; - inertia = bonus[j].inertia; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - inertia[0] = buf[m++]; - inertia[1] = buf[m++]; - inertia[2] = buf[m++]; - bonus[j].ninteger = (int) ubuf(buf[m++]).i; - bonus[j].ndouble = (int) ubuf(buf[m++]).i; - // corresponding put() calls are in clear_bonus() - bonus[j].ivalue = icp->get(bonus[j].ninteger,bonus[j].iindex); - bonus[j].dvalue = dcp->get(bonus[j].ndouble,bonus[j].dindex); - m += bptr->unpack_border_body(&bonus[j],&buf[m]); - bonus[j].ilocal = i; - body[i] = j; - nghost_bonus++; - } - } return m; } @@ -968,24 +326,11 @@ int AtomVecBody::unpack_border_hybrid(int n, int first, double *buf) xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ -int AtomVecBody::pack_exchange(int i, double *buf) +int AtomVecBody::pack_exchange_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = radius[i]; - buf[m++] = rmass[i]; - buf[m++] = angmom[i][0]; - buf[m++] = angmom[i][1]; - buf[m++] = angmom[i][2]; + int m = 0; + + int *body = atom->body; if (body[i] < 0) buf[m++] = ubuf(0).d; else { @@ -1009,40 +354,19 @@ int AtomVecBody::pack_exchange(int i, double *buf) m += bonus[j].ndouble; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ -int AtomVecBody::unpack_exchange(double *buf) +int AtomVecBody::unpack_exchange_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - radius[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - angmom[nlocal][0] = buf[m++]; - angmom[nlocal][1] = buf[m++]; - angmom[nlocal][2] = buf[m++]; - - body[nlocal] = (int) ubuf(buf[m++]).i; - if (body[nlocal] == 0) body[nlocal] = -1; + int m = 0; + + int *body = atom->body; + + body[ilocal] = (int) ubuf(buf[m++]).i; + if (body[ilocal] == 0) body[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); double *quat = bonus[nlocal_bonus].quat; @@ -1069,42 +393,34 @@ int AtomVecBody::unpack_exchange(double *buf) bonus[nlocal_bonus].ndouble*sizeof(double)); m += bonus[nlocal_bonus].ndouble; - bonus[nlocal_bonus].ilocal = nlocal; - body[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + body[ilocal] = nlocal_bonus++; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; return m; } /* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes + unpack data for one atom from restart file including bonus data ------------------------------------------------------------------------- */ -int AtomVecBody::size_restart() +int AtomVecBody::size_restart_bonus() { int i; + int *body = atom->body; + int n = 0; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) + for (i = 0; i < nlocal; i++) { if (body[i] >= 0) { - n += 26; + n += size_restart_bonus_one; if (intdoubleratio == 1) n += bonus[body[i]].ninteger; else n += (bonus[body[i]].ninteger+1)/2; n += bonus[body[i]].ndouble; - } else n += 17; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + } + n++; + } return n; } @@ -1115,25 +431,11 @@ int AtomVecBody::size_restart() molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ -int AtomVecBody::pack_restart(int i, double *buf) +int AtomVecBody::pack_restart_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = radius[i]; - buf[m++] = rmass[i]; - buf[m++] = angmom[i][0]; - buf[m++] = angmom[i][1]; - buf[m++] = angmom[i][2]; + int m = 0; + + int *body = atom->body; if (body[i] < 0) buf[m++] = ubuf(0).d; else { @@ -1157,47 +459,21 @@ int AtomVecBody::pack_restart(int i, double *buf) m += bonus[j].ndouble; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities + unpack data for one atom from restart file including bonus data ------------------------------------------------------------------------- */ -int AtomVecBody::unpack_restart(double *buf) +int AtomVecBody::unpack_restart_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } + int m = 0; + + int *body = atom->body; - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - radius[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - angmom[nlocal][0] = buf[m++]; - angmom[nlocal][1] = buf[m++]; - angmom[nlocal][2] = buf[m++]; - - body[nlocal] = (int) ubuf(buf[m++]).i; - if (body[nlocal] == 0) body[nlocal] = -1; + body[ilocal] = (int) ubuf(buf[m++]).i; + if (body[ilocal] == 0) body[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); double *quat = bonus[nlocal_bonus].quat; @@ -1222,17 +498,10 @@ int AtomVecBody::unpack_restart(double *buf) memcpy(bonus[nlocal_bonus].dvalue,&buf[m], bonus[nlocal_bonus].ndouble*sizeof(double)); m += bonus[nlocal_bonus].ndouble; - bonus[nlocal_bonus].ilocal = nlocal; - body[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + body[ilocal] = nlocal_bonus++; } - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; return m; } @@ -1241,92 +510,33 @@ int AtomVecBody::unpack_restart(double *buf) set other values to defaults ------------------------------------------------------------------------- */ -void AtomVecBody::create_atom(int itype, double *coord) +void AtomVecBody::create_atom_post(int ilocal) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - radius[nlocal] = 0.5; - rmass[nlocal] = 1.0; - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - body[nlocal] = -1; - - atom->nlocal++; + atom->radius[ilocal] = 0.5; + atom->rmass[ilocal] = 1.0; + atom->body[ilocal] = -1; } /* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecBody::data_atom(double *coord, imageint imagetmp, char **values) +void AtomVecBody::data_atom_post(int ilocal) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - body[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (body[nlocal] == 0) body[nlocal] = -1; - else if (body[nlocal] == 1) body[nlocal] = 0; - else error->one(FLERR,"Invalid bodyflag in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - radius[nlocal] = 0.5; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecBody::data_atom_hybrid(int nlocal, char **values) -{ - body[nlocal] = utils::inumeric(FLERR,values[0],true,lmp); - if (body[nlocal] == 0) body[nlocal] = -1; - else if (body[nlocal] == 1) body[nlocal] = 0; - else error->one(FLERR,"Invalid atom type in Atoms section of data file"); + body_flag = atom->body[ilocal]; + if (body_flag == 0) body_flag = -1; + else if (body_flag == 1) body_flag = 0; + else error->one(FLERR,"Invalid body flag in Atoms section of data file"); + atom->body[ilocal] = body_flag; - rmass[nlocal] = utils::numeric(FLERR,values[1],true,lmp); - if (rmass[nlocal] <= 0.0) + if (atom->rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); - return 2; + atom->radius[ilocal] = 0.5; + atom->angmom[ilocal][0] = 0.0; + atom->angmom[ilocal][1] = 0.0; + atom->angmom[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- @@ -1336,148 +546,52 @@ int AtomVecBody::data_atom_hybrid(int nlocal, char **values) void AtomVecBody::data_body(int m, int ninteger, int ndouble, int *ivalues, double *dvalues) { - if (body[m]) error->one(FLERR,"Assigning body parameters to non-body atom"); + if (atom->body[m]) + error->one(FLERR,"Assigning body parameters to non-body atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); bonus[nlocal_bonus].ilocal = m; bptr->data_body(nlocal_bonus,ninteger,ndouble,ivalues,dvalues); - body[m] = nlocal_bonus++; + atom->body[m] = nlocal_bonus++; } /* ---------------------------------------------------------------------- - unpack one tri from Velocities section of data file -------------------------------------------------------------------------- */ - -void AtomVecBody::data_vel(int m, char **values) -{ - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - angmom[m][0] = utils::numeric(FLERR,values[3],true,lmp); - angmom[m][1] = utils::numeric(FLERR,values[4],true,lmp); - angmom[m][2] = utils::numeric(FLERR,values[5],true,lmp); -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one body in Velocities section of data file + return # of bytes of allocated memory ------------------------------------------------------------------------- */ -int AtomVecBody::data_vel_hybrid(int m, char **values) +bigint AtomVecBody::memory_usage_bonus() { - angmom[m][0] = utils::numeric(FLERR,values[0],true,lmp); - angmom[m][1] = utils::numeric(FLERR,values[1],true,lmp); - angmom[m][2] = utils::numeric(FLERR,values[2],true,lmp); - return 3; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ + bigint bytes = 0; + bytes += nmax_bonus*sizeof(Bonus); + bytes += icp->size + dcp->size; -void AtomVecBody::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - if (body[i] < 0) buf[i][2] = ubuf(0).d; - else buf[i][2] = ubuf(1).d; - buf[i][3] = rmass[i]; - buf[i][4] = x[i][0]; - buf[i][5] = x[i][1]; - buf[i][6] = x[i][2]; - buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; + int nall = nlocal_bonus + nghost_bonus; + for (int i = 0; i < nall; i++) { + bytes += bonus[i].ninteger * sizeof(int); + bytes += bonus[i].ndouble * sizeof(double); } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecBody::pack_data_hybrid(int i, double *buf) -{ - if (body[i] < 0) buf[0] = ubuf(0).d; - else buf[0] = ubuf(1).d; - buf[1] = rmass[i]; - return 2; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecBody::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %d %d %g %g %g %g %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i, - buf[i][3],buf[i][4],buf[i][5],buf[i][6], - (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i, - (int) ubuf(buf[i][9]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecBody::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %d %g",(int) ubuf(buf[0]).i,buf[1]); - return 2; -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ -void AtomVecBody::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = angmom[i][0]; - buf[i][5] = angmom[i][1]; - buf[i][6] = angmom[i][2]; - } + return bytes; } /* ---------------------------------------------------------------------- - pack hybrid velocity info for data file + modify values for AtomVec::pack_data() to pack ------------------------------------------------------------------------- */ -int AtomVecBody::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = angmom[i][0]; - buf[1] = angmom[i][1]; - buf[2] = angmom[i][2]; - return 3; -} - -/* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ +void AtomVecBody::pack_data_pre(int ilocal) +{ + body_flag = atom->body[ilocal]; -void AtomVecBody::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %g %g %g %g %g %g\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3], - buf[i][4],buf[i][5],buf[i][6]); + if (body_flag < 0) atom->body[ilocal] = 0; + else atom->body[ilocal] = 1; } /* ---------------------------------------------------------------------- - write hybrid velocity info to data file + unmodify values packed by AtomVec::pack_data() ------------------------------------------------------------------------- */ -int AtomVecBody::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %g %g %g",buf[0],buf[1],buf[2]); - return 3; +void AtomVecBody::pack_data_post(int ilocal) +{ + atom->body[ilocal] = body_flag; } /* ---------------------------------------------------------------------- @@ -1497,47 +611,12 @@ double AtomVecBody::radius_body(int ninteger, int ndouble, void AtomVecBody::set_quat(int m, double *quat_external) { - if (body[m] < 0) error->one(FLERR,"Assigning quat to non-body atom"); - double *quat = bonus[body[m]].quat; + if (atom->body[m] < 0) error->one(FLERR,"Assigning quat to non-body atom"); + double *quat = bonus[atom->body[m]].quat; quat[0] = quat_external[0]; quat[1] = quat_external[1]; quat[2] = quat_external[2]; quat[3] = quat_external[3]; } -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecBody::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("radius")) bytes += memory->usage(radius,nmax); - if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); - if (atom->memcheck("angmom")) bytes += memory->usage(angmom,nmax,3); - if (atom->memcheck("torque")) bytes += - memory->usage(torque,nmax*comm->nthreads,3); - if (atom->memcheck("body")) bytes += memory->usage(body,nmax); - - bytes += nmax_bonus*sizeof(Bonus); - bytes += icp->size + dcp->size; - - int nall = nlocal_bonus + nghost_bonus; - for (int i = 0; i < nall; i++) { - bytes += bonus[i].ninteger * sizeof(int); - bytes += bonus[i].ndouble * sizeof(double); - } - - return bytes; -} - /* ---------------------------------------------------------------------- debug method for sanity checking of own/bonus data pointers ------------------------------------------------------------------------- */ diff --git a/src/atom_vec_body.h b/src/atom_vec_body.h index 38309648fb..183b4ea8ea 100644 --- a/src/atom_vec_body.h +++ b/src/atom_vec_body.h @@ -42,49 +42,26 @@ class AtomVecBody : public AtomVec { AtomVecBody(class LAMMPS *); ~AtomVecBody(); void process_args(int, char **); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); - bigint memory_usage(); - - // manipulate Bonus data structure for extra atom info + void copy_bonus(int, int, int); void clear_bonus(); + int pack_comm_bonus(int, int *, double *); + void unpack_comm_bonus(int, int, double *); + int pack_reverse_bonus(int, int, double *); + int pack_border_bonus(int, int *, double *); + int unpack_border_bonus(int, int, double *); + int pack_exchange_bonus(int, double *); + int unpack_exchange_bonus(int, double *); + int size_restart_bonus(); + int pack_restart_bonus(int, double *); + int unpack_restart_bonus(int, double *); void data_body(int, int, int, int *, double *); + bigint memory_usage_bonus(); + + void create_atom_post(int); + void data_atom_post(int); + void pack_data_pre(int); + void pack_data_post(int); // methods used by other classes to query/set body info @@ -94,23 +71,16 @@ class AtomVecBody : public AtomVec { int nlocal_bonus; private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *radius; - double *rmass; - double **angmom,**torque; - int *body; - int nghost_bonus,nmax_bonus; - int intdoubleratio; // sizeof(double) / sizeof(int) + int intdoubleratio; // sizeof(double) / sizeof(int) + int body_flag; MyPoolChunk *icp; MyPoolChunk *dcp; void grow_bonus(); - void copy_bonus(int, int); + void copy_bonus_all(int, int); + // check(int); }; } diff --git a/src/atom_vec_ellipsoid.cpp b/src/atom_vec_ellipsoid.cpp index 5565b82a10..7ba26c1c34 100644 --- a/src/atom_vec_ellipsoid.cpp +++ b/src/atom_vec_ellipsoid.cpp @@ -19,8 +19,6 @@ #include #include "math_extra.h" #include "atom.h" -#include "comm.h" -#include "domain.h" #include "modify.h" #include "fix.h" #include "math_const.h" @@ -36,74 +34,45 @@ using namespace MathConst; AtomVecEllipsoid::AtomVecEllipsoid(LAMMPS *lmp) : AtomVec(lmp) { molecular = 0; + bonus_flag = 1; - comm_x_only = comm_f_only = 0; - size_forward = 7; - size_reverse = 6; - size_border = 15; - size_velocity = 6; - size_data_atom = 7; - size_data_vel = 7; + size_forward_bonus = 4; + size_border_bonus = 8; + size_restart_bonus_one = 7; size_data_bonus = 8; - xcol_data = 5; atom->ellipsoid_flag = 1; atom->rmass_flag = atom->angmom_flag = atom->torque_flag = 1; nlocal_bonus = nghost_bonus = nmax_bonus = 0; bonus = NULL; -} - -/* ---------------------------------------------------------------------- */ -AtomVecEllipsoid::~AtomVecEllipsoid() -{ - memory->sfree(bonus); -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecEllipsoid::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); + fields_grow = (char *) "rmass angmom torque ellipsoid"; + fields_copy = (char *) "rmass angmom"; + fields_comm = NULL; + fields_comm_vel = (char *) "angmom"; + fields_reverse = (char *) "torque"; + fields_border = (char *) "rmass"; + fields_border_vel = (char *) "rmass angmom"; + fields_exchange = (char *) "rmass angmom"; + fields_restart = (char *) "rmass angmom"; + fields_create = (char *) "rmass angmom ellipsoid"; + fields_data_atom = (char *) "id type ellipsoid rmass x"; + fields_data_vel = (char *) "angmom"; - rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); - angmom = memory->grow(atom->angmom,nmax,3,"atom:angmom"); - torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque"); - ellipsoid = memory->grow(atom->ellipsoid,nmax,"atom:ellipsoid"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); + setup_fields(); } -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- */ -void AtomVecEllipsoid::grow_reset() +AtomVecEllipsoid::~AtomVecEllipsoid() { - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - rmass = atom->rmass; angmom = atom->angmom; torque = atom->torque; - ellipsoid = atom->ellipsoid; + memory->sfree(bonus); } /* ---------------------------------------------------------------------- @@ -121,31 +90,17 @@ void AtomVecEllipsoid::grow_bonus() } /* ---------------------------------------------------------------------- - copy atom I info to atom J + copy atom I bonus info to atom J ------------------------------------------------------------------------- */ -void AtomVecEllipsoid::copy(int i, int j, int delflag) +void AtomVecEllipsoid::copy_bonus(int i, int j, int delflag) { - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - rmass[j] = rmass[i]; - angmom[j][0] = angmom[i][0]; - angmom[j][1] = angmom[i][1]; - angmom[j][2] = angmom[i][2]; + int *ellipsoid = atom->ellipsoid; // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && ellipsoid[j] >= 0) { - copy_bonus(nlocal_bonus-1,ellipsoid[j]); + copy_bonus_all(nlocal_bonus-1,ellipsoid[j]); nlocal_bonus--; } @@ -154,10 +109,6 @@ void AtomVecEllipsoid::copy(int i, int j, int delflag) if (ellipsoid[i] >= 0 && i != j) bonus[ellipsoid[i]].ilocal = j; ellipsoid[j] = ellipsoid[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); } /* ---------------------------------------------------------------------- @@ -165,9 +116,9 @@ void AtomVecEllipsoid::copy(int i, int j, int delflag) also reset ellipsoid that points to I to now point to J ------------------------------------------------------------------------- */ -void AtomVecEllipsoid::copy_bonus(int i, int j) +void AtomVecEllipsoid::copy_bonus_all(int i, int j) { - ellipsoid[bonus[i].ilocal] = j; + atom->ellipsoid[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -179,194 +130,20 @@ void AtomVecEllipsoid::copy_bonus(int i, int j) void AtomVecEllipsoid::clear_bonus() { nghost_bonus = 0; -} -/* ---------------------------------------------------------------------- - set shape values in bonus data for particle I - oriented aligned with xyz axes - this may create or delete entry in bonus data -------------------------------------------------------------------------- */ - -void AtomVecEllipsoid::set_shape(int i, - double shapex, double shapey, double shapez) -{ - if (ellipsoid[i] < 0) { - if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) return; - if (nlocal_bonus == nmax_bonus) grow_bonus(); - double *shape = bonus[nlocal_bonus].shape; - double *quat = bonus[nlocal_bonus].quat; - shape[0] = shapex; - shape[1] = shapey; - shape[2] = shapez; - quat[0] = 1.0; - quat[1] = 0.0; - quat[2] = 0.0; - quat[3] = 0.0; - bonus[nlocal_bonus].ilocal = i; - ellipsoid[i] = nlocal_bonus++; - } else if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) { - copy_bonus(nlocal_bonus-1,ellipsoid[i]); - nlocal_bonus--; - ellipsoid[i] = -1; - } else { - double *shape = bonus[ellipsoid[i]].shape; - shape[0] = shapex; - shape[1] = shapey; - shape[2] = shapez; - } + if (atom->nextra_grow) + for (int iextra = 0; iextra < atom->nextra_grow; iextra++) + modify->fix[atom->extra_grow[iextra]]->clear_bonus(); } /* ---------------------------------------------------------------------- */ -int AtomVecEllipsoid::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) +int AtomVecEllipsoid::pack_comm_bonus(int n, int *list, double *buf) { int i,j,m; - double dx,dy,dz; double *quat; - m = 0; - if (pbc_flag == 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]; - if (ellipsoid[j] >= 0) { - quat = bonus[ellipsoid[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (ellipsoid[j] >= 0) { - quat = bonus[ellipsoid[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - double *quat; - - m = 0; - if (pbc_flag == 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]; - if (ellipsoid[j] >= 0) { - quat = bonus[ellipsoid[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (ellipsoid[j] >= 0) { - quat = bonus[ellipsoid[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (ellipsoid[j] >= 0) { - quat = bonus[ellipsoid[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - double *quat; + int *ellipsoid = atom->ellipsoid; m = 0; for (i = 0; i < n; i++) { @@ -379,67 +156,18 @@ int AtomVecEllipsoid::pack_comm_hybrid(int n, int *list, double *buf) buf[m++] = quat[3]; } } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEllipsoid::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - double *quat; - 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++]; - if (ellipsoid[i] >= 0) { - quat = bonus[ellipsoid[i]].quat; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - } - } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecEllipsoid::unpack_comm_vel(int n, int first, double *buf) +void AtomVecEllipsoid::unpack_comm_bonus(int n, int first, double *buf) { int i,m,last; double *quat; - 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++]; - if (ellipsoid[i] >= 0) { - quat = bonus[ellipsoid[i]].quat; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - double *quat; + int *ellipsoid = atom->ellipsoid; m = 0; last = first + n; @@ -452,294 +180,21 @@ int AtomVecEllipsoid::unpack_comm_hybrid(int n, int first, double *buf) quat[3] = buf[m++]; } } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEllipsoid::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::unpack_reverse_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } - return m; } /* ---------------------------------------------------------------------- */ -int AtomVecEllipsoid::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) +int AtomVecEllipsoid::pack_border_bonus(int n, int *list, double *buf) { int i,j,m; double dx,dy,dz; double *shape,*quat; - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rmass[j]; - if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - shape = bonus[ellipsoid[j]].shape; - quat = bonus[ellipsoid[j]].quat; - buf[m++] = shape[0]; - buf[m++] = shape[1]; - buf[m++] = shape[2]; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rmass[j]; - if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - shape = bonus[ellipsoid[j]].shape; - quat = bonus[ellipsoid[j]].quat; - buf[m++] = shape[0]; - buf[m++] = shape[1]; - buf[m++] = shape[2]; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - double *shape,*quat; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rmass[j]; - if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - shape = bonus[ellipsoid[j]].shape; - quat = bonus[ellipsoid[j]].quat; - buf[m++] = shape[0]; - buf[m++] = shape[1]; - buf[m++] = shape[2]; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rmass[j]; - if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - shape = bonus[ellipsoid[j]].shape; - quat = bonus[ellipsoid[j]].quat; - buf[m++] = shape[0]; - buf[m++] = shape[1]; - buf[m++] = shape[2]; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rmass[j]; - if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - shape = bonus[ellipsoid[j]].shape; - quat = bonus[ellipsoid[j]].quat; - buf[m++] = shape[0]; - buf[m++] = shape[1]; - buf[m++] = shape[2]; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - double *shape,*quat; + int *ellipsoid = atom->ellipsoid; m = 0; for (i = 0; i < n; i++) { j = list[i]; - buf[m++] = rmass[j]; if (ellipsoid[j] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -754,71 +209,22 @@ int AtomVecEllipsoid::pack_border_hybrid(int n, int *list, double *buf) buf[m++] = quat[3]; } } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecEllipsoid::unpack_border(int n, int first, double *buf) +int AtomVecEllipsoid::unpack_border_bonus(int n, int first, double *buf) { int i,j,m,last; double *shape,*quat; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - rmass[i] = buf[m++]; - ellipsoid[i] = (int) ubuf(buf[m++]).i; - if (ellipsoid[i] == 0) ellipsoid[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - shape = bonus[j].shape; - quat = bonus[j].quat; - shape[0] = buf[m++]; - shape[1] = buf[m++]; - shape[2] = buf[m++]; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - bonus[j].ilocal = i; - ellipsoid[i] = j; - nghost_bonus++; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecEllipsoid::unpack_border_vel(int n, int first, double *buf) -{ - int i,j,m,last; - double *shape,*quat; + int *ellipsoid = atom->ellipsoid; m = 0; last = first + n; for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - rmass[i] = buf[m++]; ellipsoid[i] = (int) ubuf(buf[m++]).i; if (ellipsoid[i] == 0) ellipsoid[i] = -1; else { @@ -837,50 +243,8 @@ void AtomVecEllipsoid::unpack_border_vel(int n, int first, double *buf) ellipsoid[i] = j; nghost_bonus++; } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; } - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecEllipsoid::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,j,m,last; - double *shape,*quat; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - rmass[i] = buf[m++]; - ellipsoid[i] = (int) ubuf(buf[m++]).i; - if (ellipsoid[i] == 0) ellipsoid[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - shape = bonus[j].shape; - quat = bonus[j].quat; - shape[0] = buf[m++]; - shape[1] = buf[m++]; - shape[2] = buf[m++]; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - bonus[j].ilocal = i; - ellipsoid[i] = j; - nghost_bonus++; - } - } return m; } @@ -889,24 +253,11 @@ int AtomVecEllipsoid::unpack_border_hybrid(int n, int first, double *buf) xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ -int AtomVecEllipsoid::pack_exchange(int i, double *buf) +int AtomVecEllipsoid::pack_exchange_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = rmass[i]; - buf[m++] = angmom[i][0]; - buf[m++] = angmom[i][1]; - buf[m++] = angmom[i][2]; + int m = 0; + + int *ellipsoid = atom->ellipsoid; if (ellipsoid[i] < 0) buf[m++] = ubuf(0).d; else { @@ -923,40 +274,19 @@ int AtomVecEllipsoid::pack_exchange(int i, double *buf) buf[m++] = quat[3]; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ -int AtomVecEllipsoid::unpack_exchange(double *buf) +int AtomVecEllipsoid::unpack_exchange_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - rmass[nlocal] = buf[m++]; - angmom[nlocal][0] = buf[m++]; - angmom[nlocal][1] = buf[m++]; - angmom[nlocal][2] = buf[m++]; - - ellipsoid[nlocal] = (int) ubuf(buf[m++]).i; - if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1; + int m = 0; + + int *ellipsoid = atom->ellipsoid; + + ellipsoid[ilocal] = (int) ubuf(buf[m++]).i; + if (ellipsoid[ilocal] == 0) ellipsoid[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); double *shape = bonus[nlocal_bonus].shape; @@ -968,16 +298,10 @@ int AtomVecEllipsoid::unpack_exchange(double *buf) quat[1] = buf[m++]; quat[2] = buf[m++]; quat[3] = buf[m++]; - bonus[nlocal_bonus].ilocal = nlocal; - ellipsoid[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + ellipsoid[ilocal] = nlocal_bonus++; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; return m; } @@ -986,20 +310,18 @@ int AtomVecEllipsoid::unpack_exchange(double *buf) include extra data stored by fixes ------------------------------------------------------------------------- */ -int AtomVecEllipsoid::size_restart() +int AtomVecEllipsoid::size_restart_bonus() { int i; + int *ellipsoid = atom->ellipsoid; + int n = 0; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (ellipsoid[i] >= 0) n += 23; - else n += 16; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + for (i = 0; i < nlocal; i++) { + if (ellipsoid[i] >= 0) n += size_restart_bonus_one; + n++; + } return n; } @@ -1010,24 +332,11 @@ int AtomVecEllipsoid::size_restart() molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ -int AtomVecEllipsoid::pack_restart(int i, double *buf) +int AtomVecEllipsoid::pack_restart_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = rmass[i]; - buf[m++] = angmom[i][0]; - buf[m++] = angmom[i][1]; - buf[m++] = angmom[i][2]; + int m = 0; + + int *ellipsoid = atom->ellipsoid; if (ellipsoid[i] < 0) buf[m++] = ubuf(0).d; else { @@ -1042,11 +351,6 @@ int AtomVecEllipsoid::pack_restart(int i, double *buf) buf[m++] = bonus[j].quat[3]; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; return m; } @@ -1054,34 +358,14 @@ int AtomVecEllipsoid::pack_restart(int i, double *buf) unpack data for one atom from restart file including bonus data ------------------------------------------------------------------------- */ -int AtomVecEllipsoid::unpack_restart(double *buf) +int AtomVecEllipsoid::unpack_restart_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } + int m = 0; - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - rmass[nlocal] = buf[m++]; - angmom[nlocal][0] = buf[m++]; - angmom[nlocal][1] = buf[m++]; - angmom[nlocal][2] = buf[m++]; - - ellipsoid[nlocal] = (int) ubuf(buf[m++]).i; - if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1; + int *ellipsoid = atom->ellipsoid; + + ellipsoid[ilocal] = (int) ubuf(buf[m++]).i; + if (ellipsoid[ilocal] == 0) ellipsoid[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); double *shape = bonus[nlocal_bonus].shape; @@ -1093,118 +377,21 @@ int AtomVecEllipsoid::unpack_restart(double *buf) quat[1] = buf[m++]; quat[2] = buf[m++]; quat[3] = buf[m++]; - bonus[nlocal_bonus].ilocal = nlocal; - ellipsoid[nlocal] = nlocal_bonus++; - } - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; + bonus[nlocal_bonus].ilocal = ilocal; + ellipsoid[ilocal] = nlocal_bonus++; } - atom->nlocal++; return m; } -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecEllipsoid::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - rmass[nlocal] = 1.0; - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - ellipsoid[nlocal] = -1; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecEllipsoid::data_atom(double *coord, imageint imagetmp, - char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - ellipsoid[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1; - else if (ellipsoid[nlocal] == 1) ellipsoid[nlocal] = 0; - else error->one(FLERR,"Invalid ellipsoidflag in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecEllipsoid::data_atom_hybrid(int nlocal, char **values) -{ - ellipsoid[nlocal] = utils::inumeric(FLERR,values[0],true,lmp); - if (ellipsoid[nlocal] == 0) ellipsoid[nlocal] = -1; - else if (ellipsoid[nlocal] == 1) ellipsoid[nlocal] = 0; - else error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[1],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - return 2; -} - /* ---------------------------------------------------------------------- unpack one line from Ellipsoids section of data file ------------------------------------------------------------------------- */ void AtomVecEllipsoid::data_atom_bonus(int m, char **values) { + int *ellipsoid = atom->ellipsoid; + if (ellipsoid[m]) error->one(FLERR,"Assigning ellipsoid parameters to non-ellipsoid atom"); @@ -1227,184 +414,113 @@ void AtomVecEllipsoid::data_atom_bonus(int m, char **values) // reset ellipsoid mass // previously stored density in rmass - rmass[m] *= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; + atom->rmass[m] *= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; bonus[nlocal_bonus].ilocal = m; ellipsoid[m] = nlocal_bonus++; } /* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file + return # of bytes of allocated bonus memory ------------------------------------------------------------------------- */ -void AtomVecEllipsoid::data_vel(int m, char **values) +bigint AtomVecEllipsoid::memory_usage_bonus() { - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - angmom[m][0] = utils::numeric(FLERR,values[3],true,lmp); - angmom[m][1] = utils::numeric(FLERR,values[4],true,lmp); - angmom[m][2] = utils::numeric(FLERR,values[5],true,lmp); + bigint bytes = 0; + bytes += nmax_bonus*sizeof(Bonus); + return bytes; } /* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file + initialize non-zero atom quantities ------------------------------------------------------------------------- */ -int AtomVecEllipsoid::data_vel_hybrid(int m, char **values) +void AtomVecEllipsoid::create_atom_post(int ilocal) { - angmom[m][0] = utils::numeric(FLERR,values[0],true,lmp); - angmom[m][1] = utils::numeric(FLERR,values[1],true,lmp); - angmom[m][2] = utils::numeric(FLERR,values[2],true,lmp); - return 3; + atom->rmass[ilocal] = 1.0; + atom->ellipsoid[ilocal] = -1; } /* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecEllipsoid::pack_data(double **buf) +void AtomVecEllipsoid::data_atom_post(int ilocal) { - double *shape; - - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - if (ellipsoid[i] < 0) buf[i][2] = ubuf(0).d; - else buf[i][2] = ubuf(1).d; - if (ellipsoid[i] < 0) buf[i][3] = rmass[i]; - else { - shape = bonus[ellipsoid[i]].shape; - buf[i][3] = rmass[i] / (4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]); - } - buf[i][4] = x[i][0]; - buf[i][5] = x[i][1]; - buf[i][6] = x[i][2]; - buf[i][7] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ + ellipsoid_flag = atom->ellipsoid[ilocal]; + if (ellipsoid_flag == 0) ellipsoid_flag = -1; + else if (ellipsoid_flag == 1) ellipsoid_flag = 0; + else error->one(FLERR,"Invalid ellipsoid flag in Atoms section of data file"); + atom->ellipsoid[ilocal] = ellipsoid_flag; -int AtomVecEllipsoid::pack_data_hybrid(int i, double *buf) -{ - if (ellipsoid[i] < 0) buf[0] = ubuf(0).d; - else buf[0] = ubuf(1).d; - if (ellipsoid[i] < 0) buf[1] = rmass[i]; - else { - double *shape = bonus[ellipsoid[i]].shape; - buf[1] = rmass[i] / (4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]); - } - return 2; + if (atom->rmass[ilocal] <= 0.0) + error->one(FLERR,"Invalid density in Atoms section of data file"); } /* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags + modify values for AtomVec::pack_data() to pack ------------------------------------------------------------------------- */ -void AtomVecEllipsoid::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i, - buf[i][3],buf[i][4],buf[i][5],buf[i][6], - (int) ubuf(buf[i][7]).i,(int) ubuf(buf[i][8]).i, - (int) ubuf(buf[i][9]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ +void AtomVecEllipsoid::pack_data_pre(int ilocal) +{ + double *shape; -int AtomVecEllipsoid::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %d %-1.16e",(int) ubuf(buf[0]).i,buf[1]); - return 2; -} + ellipsoid_flag = atom->ellipsoid[ilocal]; + rmass = atom->rmass[ilocal]; -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ + if (ellipsoid_flag < 0) atom->ellipsoid[ilocal] = 0; + else atom->ellipsoid[ilocal] = 1; -void AtomVecEllipsoid::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = angmom[i][0]; - buf[i][5] = angmom[i][1]; - buf[i][6] = angmom[i][2]; + if (ellipsoid_flag >= 0) { + shape = bonus[ellipsoid_flag].shape; + atom->rmass[ilocal] /= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; } } /* ---------------------------------------------------------------------- - pack hybrid velocity info for data file + unmodify values packed by AtomVec::pack_data() ------------------------------------------------------------------------- */ -int AtomVecEllipsoid::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = angmom[i][0]; - buf[1] = angmom[i][1]; - buf[2] = angmom[i][2]; - return 3; +void AtomVecEllipsoid::pack_data_post(int ilocal) +{ + atom->ellipsoid[ilocal] = ellipsoid_flag; + atom->rmass[ilocal] = rmass; } /* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ - -void AtomVecEllipsoid::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3], - buf[i][4],buf[i][5],buf[i][6]); -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file -------------------------------------------------------------------------- */ - -int AtomVecEllipsoid::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]); - return 3; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory + set shape values in bonus data for particle I + oriented aligned with xyz axes + this may create or delete entry in bonus data ------------------------------------------------------------------------- */ -bigint AtomVecEllipsoid::memory_usage() +void AtomVecEllipsoid:: +set_shape(int i, double shapex, double shapey, double shapez) { - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); - if (atom->memcheck("angmom")) bytes += memory->usage(angmom,nmax,3); - if (atom->memcheck("torque")) - bytes += memory->usage(torque,nmax*comm->nthreads,3); - if (atom->memcheck("ellipsoid")) bytes += memory->usage(ellipsoid,nmax); - - bytes += nmax_bonus*sizeof(Bonus); + int *ellipsoid = atom->ellipsoid; - return bytes; + if (ellipsoid[i] < 0) { + if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) return; + if (nlocal_bonus == nmax_bonus) grow_bonus(); + double *shape = bonus[nlocal_bonus].shape; + double *quat = bonus[nlocal_bonus].quat; + shape[0] = shapex; + shape[1] = shapey; + shape[2] = shapez; + quat[0] = 1.0; + quat[1] = 0.0; + quat[2] = 0.0; + quat[3] = 0.0; + bonus[nlocal_bonus].ilocal = i; + ellipsoid[i] = nlocal_bonus++; + } else if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) { + copy_bonus_all(nlocal_bonus-1,ellipsoid[i]); + nlocal_bonus--; + ellipsoid[i] = -1; + } else { + double *shape = bonus[ellipsoid[i]].shape; + shape[0] = shapex; + shape[1] = shapey; + shape[2] = shapez; + } } diff --git a/src/atom_vec_ellipsoid.h b/src/atom_vec_ellipsoid.h index d71859624e..70797c59d5 100644 --- a/src/atom_vec_ellipsoid.h +++ b/src/atom_vec_ellipsoid.h @@ -35,49 +35,26 @@ class AtomVecEllipsoid : public AtomVec { AtomVecEllipsoid(class LAMMPS *); ~AtomVecEllipsoid(); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); - bigint memory_usage(); - - // manipulate Bonus data structure for extra atom info + void copy_bonus(int, int, int); void clear_bonus(); + int pack_comm_bonus(int, int *, double *); + void unpack_comm_bonus(int, int, double *); + int pack_reverse_bonus(int, int, double *); + int pack_border_bonus(int, int *, double *); + int unpack_border_bonus(int, int, double *); + int pack_exchange_bonus(int, double *); + int unpack_exchange_bonus(int, double *); + int size_restart_bonus(); + int pack_restart_bonus(int, double *); + int unpack_restart_bonus(int, double *); void data_atom_bonus(int, char **); + bigint memory_usage_bonus(); + + void create_atom_post(int); + void data_atom_post(int); + void pack_data_pre(int); + void pack_data_post(int); // unique to AtomVecEllipsoid @@ -86,18 +63,12 @@ class AtomVecEllipsoid : public AtomVec { int nlocal_bonus; private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *rmass; - double **angmom,**torque; - int *ellipsoid; - int nghost_bonus,nmax_bonus; + int ellipsoid_flag; + double rmass; void grow_bonus(); - void copy_bonus(int, int); + void copy_bonus_all(int, int); }; } diff --git a/src/atom_vec_line.cpp b/src/atom_vec_line.cpp index 695ced13fd..3b806c959e 100644 --- a/src/atom_vec_line.cpp +++ b/src/atom_vec_line.cpp @@ -15,7 +15,6 @@ #include #include #include "atom.h" -#include "comm.h" #include "domain.h" #include "modify.h" #include "fix.h" @@ -34,16 +33,12 @@ using namespace MathConst; AtomVecLine::AtomVecLine(LAMMPS *lmp) : AtomVec(lmp) { molecular = 0; + bonus_flag = 1; - comm_x_only = comm_f_only = 0; - size_forward = 4; - size_reverse = 6; - size_border = 12; - size_velocity = 6; - size_data_atom = 8; - size_data_vel = 7; + size_forward_bonus = 1; + size_border_bonus = 3; + size_restart_bonus_one = 2; size_data_bonus = 5; - xcol_data = 6; atom->line_flag = 1; atom->molecule_flag = atom->rmass_flag = 1; @@ -52,6 +47,26 @@ AtomVecLine::AtomVecLine(LAMMPS *lmp) : AtomVec(lmp) nlocal_bonus = nghost_bonus = nmax_bonus = 0; bonus = NULL; + + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) "molecule radius rmass omega torque line"; + fields_copy = (char *) "molecule radius rmass omega"; + fields_comm = NULL; + fields_comm_vel = (char *) "omega"; + fields_reverse = (char *) "torque"; + fields_border = (char *) "molecule radius rmass"; + fields_border_vel = (char *) "molecule radius rmass omega"; + fields_exchange = (char *) "molecule radius rmass omega"; + fields_restart = (char *) "molecule radius rmass omega"; + fields_create = (char *) "molecule radius rmass omega line"; + fields_data_atom = (char *) "id molecule type line rmass x"; + fields_data_vel = (char *) "omega"; + + setup_fields(); } /* ---------------------------------------------------------------------- */ @@ -71,54 +86,6 @@ void AtomVecLine::init() error->all(FLERR,"Atom_style line can only be used in 2d simulations"); } -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecLine::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); - radius = memory->grow(atom->radius,nmax,"atom:radius"); - omega = memory->grow(atom->omega,nmax,3,"atom:omega"); - torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque"); - line = memory->grow(atom->line,nmax,"atom:line"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecLine::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - molecule = atom->molecule; rmass = atom->rmass; - radius = atom->radius; omega = atom->omega; torque = atom->torque; - line = atom->line; -} - /* ---------------------------------------------------------------------- grow bonus data structure ------------------------------------------------------------------------- */ @@ -137,30 +104,14 @@ void AtomVecLine::grow_bonus() copy atom I info to atom J ------------------------------------------------------------------------- */ -void AtomVecLine::copy(int i, int j, int delflag) +void AtomVecLine::copy_bonus(int i, int j, int delflag) { - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - molecule[j] = molecule[i]; - rmass[j] = rmass[i]; - radius[j] = radius[i]; - omega[j][0] = omega[i][0]; - omega[j][1] = omega[i][1]; - omega[j][2] = omega[i][2]; + int *line = atom->line; // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && line[j] >= 0) { - copy_bonus(nlocal_bonus-1,line[j]); + copy_bonus_all(nlocal_bonus-1,line[j]); nlocal_bonus--; } @@ -169,10 +120,6 @@ void AtomVecLine::copy(int i, int j, int delflag) if (line[i] >= 0 && i != j) bonus[line[i]].ilocal = j; line[j] = line[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); } /* ---------------------------------------------------------------------- @@ -180,9 +127,9 @@ void AtomVecLine::copy(int i, int j, int delflag) also reset line that points to I to now point to J ------------------------------------------------------------------------- */ -void AtomVecLine::copy_bonus(int i, int j) +void AtomVecLine::copy_bonus_all(int i, int j) { - line[bonus[i].ilocal] = j; + atom->line[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -200,473 +147,49 @@ void AtomVecLine::clear_bonus() modify->fix[atom->extra_grow[iextra]]->clear_bonus(); } -/* ---------------------------------------------------------------------- - set length value in bonus data for particle I - oriented along x axis - this may create or delete entry in bonus data -------------------------------------------------------------------------- */ - -void AtomVecLine::set_length(int i, double value) -{ - if (line[i] < 0) { - if (value == 0.0) return; - if (nlocal_bonus == nmax_bonus) grow_bonus(); - bonus[nlocal_bonus].length = value; - bonus[nlocal_bonus].theta = 0.0; - bonus[nlocal_bonus].ilocal = i; - line[i] = nlocal_bonus++; - } else if (value == 0.0) { - copy_bonus(nlocal_bonus-1,line[i]); - nlocal_bonus--; - line[i] = -1; - } else bonus[line[i]].length = value; - - // also set radius = half of length - // unless value = 0.0, then set diameter = 1.0 - - radius[i] = 0.5 * value; - if (value == 0.0) radius[i] = 0.5; -} - /* ---------------------------------------------------------------------- */ -int AtomVecLine::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) +int AtomVecLine::pack_comm_bonus(int n, int *list, double *buf) { int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - if (line[j] >= 0) buf[m++] = bonus[line[j]].theta; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (line[j] >= 0) buf[m++] = bonus[line[j]].theta; - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - if (line[j] >= 0) buf[m++] = bonus[line[j]].theta; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (line[j] >= 0) buf[m++] = bonus[line[j]].theta; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (line[j] >= 0) buf[m++] = bonus[line[j]].theta; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; + int *line = atom->line; m = 0; for (i = 0; i < n; i++) { j = list[i]; if (line[j] >= 0) buf[m++] = bonus[line[j]].theta; } - return m; -} - -/* ---------------------------------------------------------------------- */ -void AtomVecLine::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - if (line[i] >= 0) bonus[line[i]].theta = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecLine::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - if (line[i] >= 0) bonus[line[i]].theta = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) - if (line[i] >= 0) bonus[line[i]].theta = buf[m++]; return m; } /* ---------------------------------------------------------------------- */ -int AtomVecLine::pack_reverse(int n, int first, double *buf) +void AtomVecLine::unpack_comm_bonus(int n, int first, double *buf) { int i,m,last; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; + int *line = atom->line; m = 0; last = first + n; for (i = first; i < last; i++) { - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; + if (line[i] >= 0) bonus[line[i]].theta = buf[m++]; } - return m; } /* ---------------------------------------------------------------------- */ -void AtomVecLine::unpack_reverse(int n, int *list, double *buf) +int AtomVecLine::pack_border_bonus(int n, int *list, double *buf) { int i,j,m; - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::unpack_reverse_hybrid(int n, int *list, double *buf) -{ - int i,j,m; + int *line = atom->line; m = 0; for (i = 0; i < n; i++) { j = list[i]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (line[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - buf[m++] = bonus[line[j]].length; - buf[m++] = bonus[line[j]].theta; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (line[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - buf[m++] = bonus[line[j]].length; - buf[m++] = bonus[line[j]].theta; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (line[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - buf[m++] = bonus[line[j]].length; - buf[m++] = bonus[line[j]].theta; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (line[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - buf[m++] = bonus[line[j]].length; - buf[m++] = bonus[line[j]].theta; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (line[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - buf[m++] = bonus[line[j]].length; - buf[m++] = bonus[line[j]].theta; - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; if (line[j] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -674,66 +197,21 @@ int AtomVecLine::pack_border_hybrid(int n, int *list, double *buf) buf[m++] = bonus[line[j]].theta; } } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecLine::unpack_border(int n, int first, double *buf) +int AtomVecLine::unpack_border_bonus(int n, int first, double *buf) { int i,j,m,last; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - line[i] = (int) ubuf(buf[m++]).i; - if (line[i] == 0) line[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - bonus[j].length = buf[m++]; - bonus[j].theta = buf[m++]; - bonus[j].ilocal = i; - line[i] = j; - nghost_bonus++; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecLine::unpack_border_vel(int n, int first, double *buf) -{ - int i,j,m,last; + int *line = atom->line; m = 0; last = first + n; for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; line[i] = (int) ubuf(buf[m++]).i; if (line[i] == 0) line[i] = -1; else { @@ -745,44 +223,8 @@ void AtomVecLine::unpack_border_vel(int n, int first, double *buf) line[i] = j; nghost_bonus++; } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; } - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecLine::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,j,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - molecule[i] = (tagint) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - line[i] = (int) ubuf(buf[m++]).i; - if (line[i] == 0) line[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - bonus[j].length = buf[m++]; - bonus[j].theta = buf[m++]; - bonus[j].ilocal = i; - line[i] = j; - nghost_bonus++; - } - } return m; } @@ -791,26 +233,11 @@ int AtomVecLine::unpack_border_hybrid(int n, int first, double *buf) xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ -int AtomVecLine::pack_exchange(int i, double *buf) +int AtomVecLine::pack_exchange_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = rmass[i]; - buf[m++] = radius[i]; - buf[m++] = omega[i][0]; - buf[m++] = omega[i][1]; - buf[m++] = omega[i][2]; + int m = 0; + + int *line = atom->line; if (line[i] < 0) buf[m++] = ubuf(0).d; else { @@ -820,56 +247,27 @@ int AtomVecLine::pack_exchange(int i, double *buf) buf[m++] = bonus[j].theta; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ -int AtomVecLine::unpack_exchange(double *buf) +int AtomVecLine::unpack_exchange_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - rmass[nlocal] = buf[m++]; - radius[nlocal] = buf[m++]; - omega[nlocal][0] = buf[m++]; - omega[nlocal][1] = buf[m++]; - omega[nlocal][2] = buf[m++]; - - line[nlocal] = (int) ubuf(buf[m++]).i; - if (line[nlocal] == 0) line[nlocal] = -1; + int m = 0; + + int *line = atom->line; + + line[ilocal] = (int) ubuf(buf[m++]).i; + if (line[ilocal] == 0) line[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); bonus[nlocal_bonus].length = buf[m++]; bonus[nlocal_bonus].theta = buf[m++]; - bonus[nlocal_bonus].ilocal = nlocal; - line[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + line[ilocal] = nlocal_bonus++; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; return m; } @@ -878,20 +276,18 @@ int AtomVecLine::unpack_exchange(double *buf) include extra data stored by fixes ------------------------------------------------------------------------- */ -int AtomVecLine::size_restart() +int AtomVecLine::size_restart_bonus() { int i; + int *line = atom->line; + int n = 0; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (line[i] >= 0) n += 20; - else n += 18; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + for (i = 0; i < nlocal; i++) { + if (line[i] >= 0) n += size_restart_bonus_one; + n++; + } return n; } @@ -902,26 +298,11 @@ int AtomVecLine::size_restart() molecular types may be negative, but write as positive ------------------------------------------------------------------------- */ -int AtomVecLine::pack_restart(int i, double *buf) +int AtomVecLine::pack_restart_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = rmass[i]; - buf[m++] = radius[i]; - buf[m++] = omega[i][0]; - buf[m++] = omega[i][1]; - buf[m++] = omega[i][2]; + int m = 0; + + int *line = atom->line; if (line[i] < 0) buf[m++] = ubuf(0).d; else { @@ -931,180 +312,40 @@ int AtomVecLine::pack_restart(int i, double *buf) buf[m++] = bonus[j].theta; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities + unpack data for one atom from restart file including bonus data ------------------------------------------------------------------------- */ -int AtomVecLine::unpack_restart(double *buf) +int AtomVecLine::unpack_restart_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } + int m = 0; + + int *line = atom->line; - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - rmass[nlocal] = buf[m++]; - radius[nlocal] = buf[m++]; - omega[nlocal][0] = buf[m++]; - omega[nlocal][1] = buf[m++]; - omega[nlocal][2] = buf[m++]; - - line[nlocal] = (int) ubuf(buf[m++]).i; - if (line[nlocal] == 0) line[nlocal] = -1; + line[ilocal] = (int) ubuf(buf[m++]).i; + if (line[ilocal] == 0) line[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); bonus[nlocal_bonus].length = buf[m++]; bonus[nlocal_bonus].theta = buf[m++]; - bonus[nlocal_bonus].ilocal = nlocal; - line[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + line[ilocal] = nlocal_bonus++; } - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; return m; } -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecLine::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - molecule[nlocal] = 0; - radius[nlocal] = 0.5; - rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal]; - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - line[nlocal] = -1; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecLine::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - line[nlocal] = utils::inumeric(FLERR,values[3],true,lmp); - if (line[nlocal] == 0) line[nlocal] = -1; - else if (line[nlocal] == 1) line[nlocal] = 0; - else error->one(FLERR,"Invalid lineflag in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[4],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - if (line[nlocal] < 0) { - radius[nlocal] = 0.5; - rmass[nlocal] *= 4.0*MY_PI/3.0 * - radius[nlocal]*radius[nlocal]*radius[nlocal]; - } else radius[nlocal] = 0.0; - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecLine::data_atom_hybrid(int nlocal, char **values) -{ - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - - line[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (line[nlocal] == 0) line[nlocal] = -1; - else if (line[nlocal] == 1) line[nlocal] = 0; - else error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - if (line[nlocal] < 0) { - radius[nlocal] = 0.5; - rmass[nlocal] *= 4.0*MY_PI/3.0 * - radius[nlocal]*radius[nlocal]*radius[nlocal]; - } else radius[nlocal] = 0.0; - - return 3; -} - /* ---------------------------------------------------------------------- unpack one line from Lines section of data file ------------------------------------------------------------------------- */ void AtomVecLine::data_atom_bonus(int m, char **values) { + int *line = atom->line; + if (line[m]) error->one(FLERR,"Assigning line parameters to non-line atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); @@ -1136,186 +377,120 @@ void AtomVecLine::data_atom_bonus(int m, char **values) // reset line radius and mass // rmass currently holds density - radius[m] = 0.5 * length; - rmass[m] *= length; + atom->radius[m] = 0.5 * length; + atom->rmass[m] *= length; bonus[nlocal_bonus].ilocal = m; line[m] = nlocal_bonus++; } /* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file -------------------------------------------------------------------------- */ - -void AtomVecLine::data_vel(int m, char **values) -{ - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - omega[m][0] = utils::numeric(FLERR,values[3],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[4],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[5],true,lmp); -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file + return # of bytes of allocated bonus memory ------------------------------------------------------------------------- */ -int AtomVecLine::data_vel_hybrid(int m, char **values) +bigint AtomVecLine::memory_usage_bonus() { - omega[m][0] = utils::numeric(FLERR,values[0],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[1],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[2],true,lmp); - return 3; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecLine::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(type[i]).d; - if (line[i] < 0) buf[i][3] = ubuf(0).d; - else buf[i][3] = ubuf(1).d; - if (line[i] < 0) - buf[i][4] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); - else buf[i][4] = rmass[i]/bonus[line[i]].length; - buf[i][5] = x[i][0]; - buf[i][6] = x[i][1]; - buf[i][7] = x[i][2]; - buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } + bigint bytes = 0; + bytes += nmax_bonus*sizeof(Bonus); + return bytes; } /* ---------------------------------------------------------------------- - pack hybrid atom info for data file + create one atom of itype at coord + set other values to defaults ------------------------------------------------------------------------- */ -int AtomVecLine::pack_data_hybrid(int i, double *buf) +void AtomVecLine::create_atom_post(int ilocal) { - buf[0] = ubuf(molecule[i]).d; - if (line[i] < 0) buf[1] = ubuf(0).d; - else buf[1] = ubuf(1).d; - if (line[i] < 0) - buf[2] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); - else buf[2] = rmass[i]/bonus[line[i]].length; - return 3; + double radius = 0.5; + atom->radius[ilocal] = radius; + atom->rmass[ilocal] = 4.0*MY_PI/3.0 * radius*radius*radius; + atom->line[ilocal] = -1; } /* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecLine::write_data(FILE *fp, int n, double **buf) +void AtomVecLine::data_atom_post(int ilocal) { - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i,(int) ubuf(buf[i][3]).i, - buf[i][4],buf[i][5],buf[i][6],buf[i][7], - (int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i, - (int) ubuf(buf[i][10]).i); -} + line_flag = atom->line[ilocal]; + if (line_flag == 0) line_flag = -1; + else if (line_flag == 1) line_flag = 0; + else error->one(FLERR,"Invalid line flag in Atoms section of data file"); + atom->line[ilocal] = line_flag; -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ + if (atom->rmass[ilocal] <= 0.0) + error->one(FLERR,"Invalid density in Atoms section of data file"); -int AtomVecLine::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT " %d %-1.16e", - (tagint) ubuf(buf[0]).i,(int) ubuf(buf[1]).i,buf[2]); - return 3; -} + if (line_flag < 0) { + double radius = 0.5; + atom->radius[ilocal] = radius; + atom->rmass[ilocal] *= 4.0*MY_PI/3.0 * radius*radius*radius; + } else atom->radius[ilocal] = 0.0; -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ - -void AtomVecLine::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = omega[i][0]; - buf[i][5] = omega[i][1]; - buf[i][6] = omega[i][2]; - } + atom->omega[ilocal][0] = 0.0; + atom->omega[ilocal][1] = 0.0; + atom->omega[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- - pack hybrid velocity info for data file + modify values for AtomVec::pack_data() to pack ------------------------------------------------------------------------- */ -int AtomVecLine::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = omega[i][0]; - buf[1] = omega[i][1]; - buf[2] = omega[i][2]; - return 3; -} +void AtomVecLine::pack_data_pre(int ilocal) +{ + line_flag = atom->line[ilocal]; + rmass = atom->rmass[ilocal]; -/* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ + if (line_flag < 0) atom->line[ilocal] = 0; + else atom->line[ilocal] = 1; -void AtomVecLine::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3], - buf[i][4],buf[i][5],buf[i][6]); + if (line_flag < 0) { + double radius = atom->radius[ilocal]; + atom->rmass[ilocal] /= 4.0*MY_PI/3.0 * radius*radius*radius; + } else atom->rmass[ilocal] /= bonus[line_flag].length; } /* ---------------------------------------------------------------------- - write hybrid velocity info to data file + unmodify values packed by AtomVec::pack_data() ------------------------------------------------------------------------- */ -int AtomVecLine::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]); - return 3; +void AtomVecLine::pack_data_post(int ilocal) +{ + atom->line[ilocal] = line_flag; + atom->rmass[ilocal] = rmass; } /* ---------------------------------------------------------------------- - return # of bytes of allocated memory + set length value in bonus data for particle I + oriented along x axis + this may create or delete entry in bonus data ------------------------------------------------------------------------- */ -bigint AtomVecLine::memory_usage() +void AtomVecLine::set_length(int i, double value) { - bigint bytes = 0; + int *line = atom->line; - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); - if (atom->memcheck("radius")) bytes += memory->usage(radius,nmax); - if (atom->memcheck("omega")) bytes += memory->usage(omega,nmax,3); - if (atom->memcheck("torque")) - bytes += memory->usage(torque,nmax*comm->nthreads,3); - if (atom->memcheck("line")) bytes += memory->usage(line,nmax); + if (line[i] < 0) { + if (value == 0.0) return; + if (nlocal_bonus == nmax_bonus) grow_bonus(); + bonus[nlocal_bonus].length = value; + bonus[nlocal_bonus].theta = 0.0; + bonus[nlocal_bonus].ilocal = i; + line[i] = nlocal_bonus++; + } else if (value == 0.0) { + copy_bonus_all(nlocal_bonus-1,line[i]); + nlocal_bonus--; + line[i] = -1; + } else bonus[line[i]].length = value; - bytes += nmax_bonus*sizeof(Bonus); + // also set radius = half of length + // unless value = 0.0, then set diameter = 1.0 - return bytes; + atom->radius[i] = 0.5 * value; + if (value == 0.0) atom->radius[i] = 0.5; } /* ---------------------------------------------------------------------- diff --git a/src/atom_vec_line.h b/src/atom_vec_line.h index 6c8701cfc2..a8bc8fd1bc 100644 --- a/src/atom_vec_line.h +++ b/src/atom_vec_line.h @@ -35,49 +35,26 @@ class AtomVecLine : public AtomVec { AtomVecLine(class LAMMPS *); ~AtomVecLine(); void init(); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); - bigint memory_usage(); - - // manipulate Bonus data structure for extra atom info + void copy_bonus(int, int, int); void clear_bonus(); + int pack_comm_bonus(int, int *, double *); + void unpack_comm_bonus(int, int, double *); + int pack_reverse_bonus(int, int, double *); + int pack_border_bonus(int, int *, double *); + int unpack_border_bonus(int, int, double *); + int pack_exchange_bonus(int, double *); + int unpack_exchange_bonus(int, double *); + int size_restart_bonus(); + int pack_restart_bonus(int, double *); + int unpack_restart_bonus(int, double *); void data_atom_bonus(int, char **); + bigint memory_usage_bonus(); + + void create_atom_post(int); + void data_atom_post(int); + void pack_data_pre(int); + void pack_data_post(int); // unique to AtomVecLine @@ -86,19 +63,12 @@ class AtomVecLine : public AtomVec { int nlocal_bonus; private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - tagint *molecule; - double *rmass,*radius; - double **omega,**torque; - int *line; - int nghost_bonus,nmax_bonus; + int line_flag; + double rmass; void grow_bonus(); - void copy_bonus(int, int); + void copy_bonus_all(int, int); // void consistency_check(int, char *); }; diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index b44aa69035..5ae4c0ca21 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -94,7 +94,7 @@ void AtomVecSphere::init() } /* ---------------------------------------------------------------------- - initialize other atom quantities + initialize non-zero atom quantities ------------------------------------------------------------------------- */ void AtomVecSphere::create_atom_post(int ilocal) @@ -117,7 +117,7 @@ void AtomVecSphere::data_atom_post(int ilocal) 4.0*MY_PI/3.0 * radius*radius*radius * atom->rmass[ilocal]; if (atom->rmass[ilocal] <= 0.0) - error->one(FLERR,"Invalid mass in Atoms section of data file"); + error->one(FLERR,"Invalid density in Atoms section of data file"); } /* ---------------------------------------------------------------------- diff --git a/src/atom_vec_tri.cpp b/src/atom_vec_tri.cpp index 3b7bfe5377..6da0ef7015 100644 --- a/src/atom_vec_tri.cpp +++ b/src/atom_vec_tri.cpp @@ -16,7 +16,6 @@ #include #include "math_extra.h" #include "atom.h" -#include "comm.h" #include "domain.h" #include "modify.h" #include "fix.h" @@ -35,16 +34,12 @@ using namespace MathConst; AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp) { molecular = 0; + bonus_flag = 1; - comm_x_only = comm_f_only = 0; - size_forward = 7; - size_reverse = 6; - size_border = 26; - size_velocity = 9; - size_data_atom = 8; - size_data_vel = 7; + size_forward_bonus = 4; + size_border_bonus = 17; + size_restart_bonus_one = 16; size_data_bonus = 10; - xcol_data = 6; atom->tri_flag = 1; atom->molecule_flag = atom->rmass_flag = 1; @@ -55,8 +50,25 @@ AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp) nlocal_bonus = nghost_bonus = nmax_bonus = 0; bonus = NULL; - if (domain->dimension != 3) - error->all(FLERR,"Atom_style tri can only be used in 3d simulations"); + // strings with peratom variables to include in each AtomVec method + // strings cannot contain fields in corresponding AtomVec default strings + // order of fields in the string does not matter + // except fields_data_atom and fields_data_vel which must match data file + + fields_grow = (char *) "molecule radius rmass omega angmom torque tri"; + fields_copy = (char *) "molecule radius rmass omega angmom"; + fields_comm = NULL; + fields_comm_vel = (char *) "omega angmom"; + fields_reverse = (char *) "torque"; + fields_border = (char *) "molecule radius rmass"; + fields_border_vel = (char *) "molecule radius rmass omega"; + fields_exchange = (char *) "molecule radius rmass omega angmom"; + fields_restart = (char *) "molecule radius rmass omega angmom"; + fields_create = (char *) "molecule radius rmass omega angmom line"; + fields_data_atom = (char *) "id molecule type tri rmass x"; + fields_data_vel = (char *) "omega angmom"; + + setup_fields(); } /* ---------------------------------------------------------------------- */ @@ -76,56 +88,6 @@ void AtomVecTri::init() error->all(FLERR,"Atom_style tri can only be used in 3d simulations"); } -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecTri::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - molecule = memory->grow(atom->molecule,nmax,"atom:molecule"); - rmass = memory->grow(atom->rmass,nmax,"atom:rmass"); - radius = memory->grow(atom->radius,nmax,"atom:radius"); - omega = memory->grow(atom->omega,nmax,3,"atom:omega"); - angmom = memory->grow(atom->angmom,nmax,3,"atom:angmom"); - torque = memory->grow(atom->torque,nmax*comm->nthreads,3,"atom:torque"); - tri = memory->grow(atom->tri,nmax,"atom:tri"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecTri::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - molecule = atom->molecule; rmass = atom->rmass; - radius = atom->radius; omega = atom->omega; - angmom = atom->angmom; torque = atom->torque; - tri = atom->tri; -} - /* ---------------------------------------------------------------------- grow bonus data structure ------------------------------------------------------------------------- */ @@ -145,33 +107,14 @@ void AtomVecTri::grow_bonus() if delflag and atom J has bonus data, then delete it ------------------------------------------------------------------------- */ -void AtomVecTri::copy(int i, int j, int delflag) +void AtomVecTri::copy_bonus(int i, int j, int delflag) { - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - molecule[j] = molecule[i]; - rmass[j] = rmass[i]; - radius[j] = radius[i]; - omega[j][0] = omega[i][0]; - omega[j][1] = omega[i][1]; - omega[j][2] = omega[i][2]; - angmom[j][0] = angmom[i][0]; - angmom[j][1] = angmom[i][1]; - angmom[j][2] = angmom[i][2]; + int *tri = atom->tri; // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && tri[j] >= 0) { - copy_bonus(nlocal_bonus-1,tri[j]); + copy_bonus_all(nlocal_bonus-1,tri[j]); nlocal_bonus--; } @@ -180,10 +123,6 @@ void AtomVecTri::copy(int i, int j, int delflag) if (tri[i] >= 0 && i != j) bonus[tri[i]].ilocal = j; tri[j] = tri[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); } /* ---------------------------------------------------------------------- @@ -191,9 +130,9 @@ void AtomVecTri::copy(int i, int j, int delflag) also reset tri that points to I to now point to J ------------------------------------------------------------------------- */ -void AtomVecTri::copy_bonus(int i, int j) +void AtomVecTri::copy_bonus_all(int i, int j) { - tri[bonus[i].ilocal] = j; + atom->tri[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -211,232 +150,14 @@ void AtomVecTri::clear_bonus() modify->fix[atom->extra_grow[iextra]]->clear_bonus(); } -/* ---------------------------------------------------------------------- - set equilateral tri of size in bonus data for particle I - oriented symmetrically in xy plane - this may create or delete entry in bonus data -------------------------------------------------------------------------- */ - -void AtomVecTri::set_equilateral(int i, double size) -{ - // also set radius = distance from center to corner-pt = len(c1) - // unless size = 0.0, then set diameter = 1.0 - - if (tri[i] < 0) { - if (size == 0.0) return; - if (nlocal_bonus == nmax_bonus) grow_bonus(); - double *quat = bonus[nlocal_bonus].quat; - double *c1 = bonus[nlocal_bonus].c1; - double *c2 = bonus[nlocal_bonus].c2; - double *c3 = bonus[nlocal_bonus].c3; - double *inertia = bonus[nlocal_bonus].inertia; - quat[0] = 1.0; - quat[1] = 0.0; - quat[2] = 0.0; - quat[3] = 0.0; - c1[0] = -size/2.0; - c1[1] = -sqrt(3.0)/2.0 * size / 3.0; - c1[2] = 0.0; - c2[0] = size/2.0; - c2[1] = -sqrt(3.0)/2.0 * size / 3.0; - c2[2] = 0.0; - c3[0] = 0.0; - c3[1] = sqrt(3.0)/2.0 * size * 2.0/3.0; - c3[2] = 0.0; - inertia[0] = sqrt(3.0)/96.0 * size*size*size*size; - inertia[1] = sqrt(3.0)/96.0 * size*size*size*size; - inertia[2] = sqrt(3.0)/48.0 * size*size*size*size; - radius[i] = MathExtra::len3(c1); - bonus[nlocal_bonus].ilocal = i; - tri[i] = nlocal_bonus++; - } else if (size == 0.0) { - radius[i] = 0.5; - copy_bonus(nlocal_bonus-1,tri[i]); - nlocal_bonus--; - tri[i] = -1; - } else { - double *c1 = bonus[tri[i]].c1; - double *c2 = bonus[tri[i]].c2; - double *c3 = bonus[tri[i]].c3; - double *inertia = bonus[tri[i]].inertia; - c1[0] = -size/2.0; - c1[1] = -sqrt(3.0)/2.0 * size / 3.0; - c1[2] = 0.0; - c2[0] = size/2.0; - c2[1] = -sqrt(3.0)/2.0 * size / 3.0; - c2[2] = 0.0; - c3[0] = 0.0; - c3[1] = sqrt(3.0)/2.0 * size * 2.0/3.0; - c3[2] = 0.0; - inertia[0] = sqrt(3.0)/96.0 * size*size*size*size; - inertia[1] = sqrt(3.0)/96.0 * size*size*size*size; - inertia[2] = sqrt(3.0)/48.0 * size*size*size*size; - radius[i] = MathExtra::len3(c1); - } -} - /* ---------------------------------------------------------------------- */ -int AtomVecTri::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) +int AtomVecTri::pack_comm_bonus(int n, int *list, double *buf) { int i,j,m; - double dx,dy,dz; double *quat; - m = 0; - if (pbc_flag == 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]; - if (tri[j] >= 0) { - quat = bonus[tri[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (tri[j] >= 0) { - quat = bonus[tri[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - double *quat; - - m = 0; - if (pbc_flag == 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]; - if (tri[j] >= 0) { - quat = bonus[tri[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (tri[j] >= 0) { - quat = bonus[tri[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (tri[j] >= 0) { - quat = bonus[tri[j]].quat; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - double *quat; + int *tri = atom->tri; m = 0; for (i = 0; i < n; i++) { @@ -449,74 +170,22 @@ int AtomVecTri::pack_comm_hybrid(int n, int *list, double *buf) buf[m++] = quat[3]; } } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecTri::unpack_comm(int n, int first, double *buf) +void AtomVecTri::unpack_comm_bonus(int n, int first, double *buf) { int i,m,last; double *quat; - 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++]; - if (tri[i] >= 0) { - quat = bonus[tri[i]].quat; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - } - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTri::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - double *quat; + int *tri = atom->tri; 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++]; - if (tri[i] >= 0) { - quat = bonus[tri[i]].quat; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - double *quat; - - m = 0; - last = first + n; - for (i = first; i < last; i++) if (tri[i] >= 0) { quat = bonus[tri[i]].quat; quat[0] = buf[m++]; @@ -524,375 +193,21 @@ int AtomVecTri::unpack_comm_hybrid(int n, int first, double *buf) quat[2] = buf[m++]; quat[3] = buf[m++]; } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = torque[i][0]; - buf[m++] = torque[i][1]; - buf[m++] = torque[i][2]; } - return m; } /* ---------------------------------------------------------------------- */ -void AtomVecTri::unpack_reverse(int n, int *list, double *buf) +int AtomVecTri::pack_border_bonus(int n, int *list, double *buf) { int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::unpack_reverse_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - torque[j][0] += buf[m++]; - torque[j][1] += buf[m++]; - torque[j][2] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; double *quat,*c1,*c2,*c3,*inertia; - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (tri[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[tri[j]].quat; - c1 = bonus[tri[j]].c1; - c2 = bonus[tri[j]].c2; - c3 = bonus[tri[j]].c3; - inertia = bonus[tri[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = c1[0]; - buf[m++] = c1[1]; - buf[m++] = c1[2]; - buf[m++] = c2[0]; - buf[m++] = c2[1]; - buf[m++] = c2[2]; - buf[m++] = c3[0]; - buf[m++] = c3[1]; - buf[m++] = c3[2]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - } - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (tri[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[tri[j]].quat; - c1 = bonus[tri[j]].c1; - c2 = bonus[tri[j]].c2; - c3 = bonus[tri[j]].c3; - inertia = bonus[tri[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = c1[0]; - buf[m++] = c1[1]; - buf[m++] = c1[2]; - buf[m++] = c2[0]; - buf[m++] = c2[1]; - buf[m++] = c2[2]; - buf[m++] = c3[0]; - buf[m++] = c3[1]; - buf[m++] = c3[2]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - double *quat,*c1,*c2,*c3,*inertia; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (tri[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[tri[j]].quat; - c1 = bonus[tri[j]].c1; - c2 = bonus[tri[j]].c2; - c3 = bonus[tri[j]].c3; - inertia = bonus[tri[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = c1[0]; - buf[m++] = c1[1]; - buf[m++] = c1[2]; - buf[m++] = c2[0]; - buf[m++] = c2[1]; - buf[m++] = c2[2]; - buf[m++] = c3[0]; - buf[m++] = c3[1]; - buf[m++] = c3[2]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (tri[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[tri[j]].quat; - c1 = bonus[tri[j]].c1; - c2 = bonus[tri[j]].c2; - c3 = bonus[tri[j]].c3; - inertia = bonus[tri[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = c1[0]; - buf[m++] = c1[1]; - buf[m++] = c1[2]; - buf[m++] = c2[0]; - buf[m++] = c2[1]; - buf[m++] = c2[2]; - buf[m++] = c3[0]; - buf[m++] = c3[1]; - buf[m++] = c3[2]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - } - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - if (tri[j] < 0) buf[m++] = ubuf(0).d; - else { - buf[m++] = ubuf(1).d; - quat = bonus[tri[j]].quat; - c1 = bonus[tri[j]].c1; - c2 = bonus[tri[j]].c2; - c3 = bonus[tri[j]].c3; - inertia = bonus[tri[j]].inertia; - buf[m++] = quat[0]; - buf[m++] = quat[1]; - buf[m++] = quat[2]; - buf[m++] = quat[3]; - buf[m++] = c1[0]; - buf[m++] = c1[1]; - buf[m++] = c1[2]; - buf[m++] = c2[0]; - buf[m++] = c2[1]; - buf[m++] = c2[2]; - buf[m++] = c3[0]; - buf[m++] = c3[1]; - buf[m++] = c3[2]; - buf[m++] = inertia[0]; - buf[m++] = inertia[1]; - buf[m++] = inertia[2]; - } - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = omega[j][0]; - buf[m++] = omega[j][1]; - buf[m++] = omega[j][2]; - buf[m++] = angmom[j][0]; - buf[m++] = angmom[j][1]; - buf[m++] = angmom[j][2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - double *quat,*c1,*c2,*c3,*inertia; + int *tri = atom->tri; m = 0; for (i = 0; i < n; i++) { j = list[i]; - buf[m++] = ubuf(molecule[j]).d; - buf[m++] = radius[j]; - buf[m++] = rmass[j]; if (tri[j] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -919,87 +234,22 @@ int AtomVecTri::pack_border_hybrid(int n, int *list, double *buf) buf[m++] = inertia[2]; } } + return m; } /* ---------------------------------------------------------------------- */ -void AtomVecTri::unpack_border(int n, int first, double *buf) +int AtomVecTri::unpack_border_bonus(int n, int first, double *buf) { int i,j,m,last; double *quat,*c1,*c2,*c3,*inertia; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - tri[i] = (int) ubuf(buf[m++]).i; - if (tri[i] == 0) tri[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - quat = bonus[j].quat; - c1 = bonus[j].c1; - c2 = bonus[j].c2; - c3 = bonus[j].c3; - inertia = bonus[j].inertia; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - c1[0] = buf[m++]; - c1[1] = buf[m++]; - c1[2] = buf[m++]; - c2[0] = buf[m++]; - c2[1] = buf[m++]; - c2[2] = buf[m++]; - c3[0] = buf[m++]; - c3[1] = buf[m++]; - c3[2] = buf[m++]; - inertia[0] = buf[m++]; - inertia[1] = buf[m++]; - inertia[2] = buf[m++]; - bonus[j].ilocal = i; - tri[i] = j; - nghost_bonus++; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTri::unpack_border_vel(int n, int first, double *buf) -{ - int i,j,m,last; - double *quat,*c1,*c2,*c3,*inertia; + int *tri = atom->tri; m = 0; last = first + n; for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; tri[i] = (int) ubuf(buf[m++]).i; if (tri[i] == 0) tri[i] = -1; else { @@ -1030,67 +280,8 @@ void AtomVecTri::unpack_border_vel(int n, int first, double *buf) tri[i] = j; nghost_bonus++; } - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - omega[i][0] = buf[m++]; - omega[i][1] = buf[m++]; - omega[i][2] = buf[m++]; - angmom[i][0] = buf[m++]; - angmom[i][1] = buf[m++]; - angmom[i][2] = buf[m++]; } - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTri::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,j,m,last; - double *quat,*c1,*c2,*c3,*inertia; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - molecule[i] = (tagint) ubuf(buf[m++]).i; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - tri[i] = (int) ubuf(buf[m++]).i; - if (tri[i] == 0) tri[i] = -1; - else { - j = nlocal_bonus + nghost_bonus; - if (j == nmax_bonus) grow_bonus(); - quat = bonus[j].quat; - c1 = bonus[j].c1; - c2 = bonus[j].c2; - c3 = bonus[j].c3; - inertia = bonus[j].inertia; - quat[0] = buf[m++]; - quat[1] = buf[m++]; - quat[2] = buf[m++]; - quat[3] = buf[m++]; - c1[0] = buf[m++]; - c1[1] = buf[m++]; - c1[2] = buf[m++]; - c2[0] = buf[m++]; - c2[1] = buf[m++]; - c2[2] = buf[m++]; - c3[0] = buf[m++]; - c3[1] = buf[m++]; - c3[2] = buf[m++]; - inertia[0] = buf[m++]; - inertia[1] = buf[m++]; - inertia[2] = buf[m++]; - bonus[j].ilocal = i; - tri[i] = j; - nghost_bonus++; - } - } return m; } @@ -1099,29 +290,11 @@ int AtomVecTri::unpack_border_hybrid(int n, int first, double *buf) xyz must be 1st 3 values, so comm::exchange() can test on them ------------------------------------------------------------------------- */ -int AtomVecTri::pack_exchange(int i, double *buf) +int AtomVecTri::pack_exchange_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = rmass[i]; - buf[m++] = radius[i]; - buf[m++] = omega[i][0]; - buf[m++] = omega[i][1]; - buf[m++] = omega[i][2]; - buf[m++] = angmom[i][0]; - buf[m++] = angmom[i][1]; - buf[m++] = angmom[i][2]; + int m = 0; + + int *tri = atom->tri; if (tri[i] < 0) buf[m++] = ubuf(0).d; else { @@ -1150,45 +323,19 @@ int AtomVecTri::pack_exchange(int i, double *buf) buf[m++] = inertia[2]; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- */ -int AtomVecTri::unpack_exchange(double *buf) +int AtomVecTri::unpack_exchange_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - rmass[nlocal] = buf[m++]; - radius[nlocal] = buf[m++]; - omega[nlocal][0] = buf[m++]; - omega[nlocal][1] = buf[m++]; - omega[nlocal][2] = buf[m++]; - angmom[nlocal][0] = buf[m++]; - angmom[nlocal][1] = buf[m++]; - angmom[nlocal][2] = buf[m++]; - - tri[nlocal] = (int) ubuf(buf[m++]).i; - if (tri[nlocal] == 0) tri[nlocal] = -1; + int m = 0; + + int *tri = atom->tri; + + tri[ilocal] = (int) ubuf(buf[m++]).i; + if (tri[ilocal] == 0) tri[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); double *quat = bonus[nlocal_bonus].quat; @@ -1212,16 +359,10 @@ int AtomVecTri::unpack_exchange(double *buf) inertia[0] = buf[m++]; inertia[1] = buf[m++]; inertia[2] = buf[m++]; - bonus[nlocal_bonus].ilocal = nlocal; - tri[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + tri[ilocal] = nlocal_bonus++; } - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; return m; } @@ -1230,53 +371,31 @@ int AtomVecTri::unpack_exchange(double *buf) include extra data stored by fixes ------------------------------------------------------------------------- */ -int AtomVecTri::size_restart() +int AtomVecTri::size_restart_bonus() { int i; + int *tri = atom->tri; + int n = 0; int nlocal = atom->nlocal; - for (i = 0; i < nlocal; i++) - if (tri[i] >= 0) n += 37; - else n += 21; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); + for (i = 0; i < nlocal; i++) { + if (tri[i] >= 0) n += size_restart_bonus_one; + n++; + } return n; } /* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive + unpack data for one atom from restart file including bonus data ------------------------------------------------------------------------- */ -int AtomVecTri::pack_restart(int i, double *buf) +int AtomVecTri::pack_restart_bonus(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = rmass[i]; - buf[m++] = radius[i]; - buf[m++] = omega[i][0]; - buf[m++] = omega[i][1]; - buf[m++] = omega[i][2]; - buf[m++] = angmom[i][0]; - buf[m++] = angmom[i][1]; - buf[m++] = angmom[i][2]; + int m = 0; + + int *tri = atom->tri; if (tri[i] < 0) buf[m++] = ubuf(0).d; else { @@ -1305,51 +424,21 @@ int AtomVecTri::pack_restart(int i, double *buf) buf[m++] = inertia[2]; } - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; return m; } /* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities + unpack data for one atom from restart file including bonus data ------------------------------------------------------------------------- */ -int AtomVecTri::unpack_restart(double *buf) +int AtomVecTri::unpack_restart_bonus(int ilocal, double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } + int m = 0; - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; - rmass[nlocal] = buf[m++]; - radius[nlocal] = buf[m++]; - omega[nlocal][0] = buf[m++]; - omega[nlocal][1] = buf[m++]; - omega[nlocal][2] = buf[m++]; - angmom[nlocal][0] = buf[m++]; - angmom[nlocal][1] = buf[m++]; - angmom[nlocal][2] = buf[m++]; - - tri[nlocal] = (int) ubuf(buf[m++]).i; - if (tri[nlocal] == 0) tri[nlocal] = -1; + int *tri = atom->tri; + + tri[ilocal] = (int) ubuf(buf[m++]).i; + if (tri[ilocal] == 0) tri[ilocal] = -1; else { if (nlocal_bonus == nmax_bonus) grow_bonus(); double *quat = bonus[nlocal_bonus].quat; @@ -1373,140 +462,21 @@ int AtomVecTri::unpack_restart(double *buf) inertia[0] = buf[m++]; inertia[1] = buf[m++]; inertia[2] = buf[m++]; - bonus[nlocal_bonus].ilocal = nlocal; - tri[nlocal] = nlocal_bonus++; + bonus[nlocal_bonus].ilocal = ilocal; + tri[ilocal] = nlocal_bonus++; } - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; return m; } -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecTri::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - molecule[nlocal] = 0; - radius[nlocal] = 0.5; - rmass[nlocal] = 4.0*MY_PI/3.0 * radius[nlocal]*radius[nlocal]*radius[nlocal]; - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - tri[nlocal] = -1; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecTri::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - molecule[nlocal] = utils::tnumeric(FLERR,values[1],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[2],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - tri[nlocal] = utils::inumeric(FLERR,values[3],true,lmp); - if (tri[nlocal] == 0) tri[nlocal] = -1; - else if (tri[nlocal] == 1) tri[nlocal] = 0; - else error->one(FLERR,"Invalid triflag in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[4],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - if (tri[nlocal] < 0) { - radius[nlocal] = 0.5; - rmass[nlocal] *= 4.0*MY_PI/3.0 * - radius[nlocal]*radius[nlocal]*radius[nlocal]; - } else radius[nlocal] = 0.0; - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - omega[nlocal][0] = 0.0; - omega[nlocal][1] = 0.0; - omega[nlocal][2] = 0.0; - angmom[nlocal][0] = 0.0; - angmom[nlocal][1] = 0.0; - angmom[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one tri in Atoms section of data file - initialize other atom quantities for this sub-style -------------------------------------------------------------------------- */ - -int AtomVecTri::data_atom_hybrid(int nlocal, char **values) -{ - molecule[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - - tri[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (tri[nlocal] == 0) tri[nlocal] = -1; - else if (tri[nlocal] == 1) tri[nlocal] = 0; - else error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - if (rmass[nlocal] <= 0.0) - error->one(FLERR,"Invalid density in Atoms section of data file"); - - if (tri[nlocal] < 0) { - radius[nlocal] = 0.5; - rmass[nlocal] *= 4.0*MY_PI/3.0 * - radius[nlocal]*radius[nlocal]*radius[nlocal]; - } else radius[nlocal] = 0.0; - - return 3; -} - /* ---------------------------------------------------------------------- unpack one line from Tris section of data file ------------------------------------------------------------------------- */ void AtomVecTri::data_atom_bonus(int m, char **values) { + int *tri = atom->tri; + if (tri[m]) error->one(FLERR,"Assigning tri parameters to non-tri atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); @@ -1553,9 +523,9 @@ void AtomVecTri::data_atom_bonus(int m, char **values) if (delta/size > EPSILON) error->one(FLERR,"Inconsistent triangle in data file"); - x[m][0] = centroid[0]; - x[m][1] = centroid[1]; - x[m][2] = centroid[2]; + atom->x[m][0] = centroid[0]; + atom->x[m][1] = centroid[1]; + atom->x[m][2] = centroid[2]; // reset tri radius and mass // rmass currently holds density @@ -1563,22 +533,22 @@ void AtomVecTri::data_atom_bonus(int m, char **values) double c4[3]; MathExtra::sub3(c1,centroid,c4); - radius[m] = MathExtra::lensq3(c4); + atom->radius[m] = MathExtra::lensq3(c4); MathExtra::sub3(c2,centroid,c4); - radius[m] = MAX(radius[m],MathExtra::lensq3(c4)); + atom->radius[m] = MAX(atom->radius[m],MathExtra::lensq3(c4)); MathExtra::sub3(c3,centroid,c4); - radius[m] = MAX(radius[m],MathExtra::lensq3(c4)); - radius[m] = sqrt(radius[m]); + atom->radius[m] = MAX(atom->radius[m],MathExtra::lensq3(c4)); + atom->radius[m] = sqrt(atom->radius[m]); double norm[3]; MathExtra::cross3(c2mc1,c3mc1,norm); double area = 0.5 * MathExtra::len3(norm); - rmass[m] *= area; + atom->rmass[m] *= area; // inertia = inertia tensor of triangle as 6-vector in Voigt notation double inertia[6]; - MathExtra::inertia_triangle(c1,c2,c3,rmass[m],inertia); + MathExtra::inertia_triangle(c1,c2,c3,atom->rmass[m],inertia); // diagonalize inertia tensor via Jacobi rotations // bonus[].inertia = 3 eigenvalues = principal moments of inertia @@ -1635,207 +605,156 @@ void AtomVecTri::data_atom_bonus(int m, char **values) } /* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file + return # of bytes of allocated bonus memory ------------------------------------------------------------------------- */ -void AtomVecTri::data_vel(int m, char **values) +bigint AtomVecTri::memory_usage_bonus() { - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - omega[m][0] = utils::numeric(FLERR,values[3],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[4],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[5],true,lmp); - angmom[m][0] = utils::numeric(FLERR,values[6],true,lmp); - angmom[m][1] = utils::numeric(FLERR,values[7],true,lmp); - angmom[m][2] = utils::numeric(FLERR,values[8],true,lmp); + bigint bytes = 0; + bytes += nmax_bonus*sizeof(Bonus); + return bytes; } /* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file + create one atom of itype at coord + set other values to defaults ------------------------------------------------------------------------- */ -int AtomVecTri::data_vel_hybrid(int m, char **values) +void AtomVecTri::create_atom_post(int ilocal) { - omega[m][0] = utils::numeric(FLERR,values[0],true,lmp); - omega[m][1] = utils::numeric(FLERR,values[1],true,lmp); - omega[m][2] = utils::numeric(FLERR,values[2],true,lmp); - angmom[m][0] = utils::numeric(FLERR,values[3],true,lmp); - angmom[m][1] = utils::numeric(FLERR,values[4],true,lmp); - angmom[m][2] = utils::numeric(FLERR,values[5],true,lmp); - return 6; + double radius = 0.5; + atom->radius[ilocal] = radius; + atom->rmass[ilocal] = 4.0*MY_PI/3.0 * radius*radius*radius; + atom->tri[ilocal] = -1; } /* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecTri::pack_data(double **buf) +void AtomVecTri::data_atom_post(int ilocal) { - double c2mc1[3],c3mc1[3],norm[3]; - double area; + tri_flag = atom->tri[ilocal]; + if (tri_flag == 0) tri_flag = -1; + else if (tri_flag == 1) tri_flag = 0; + else error->one(FLERR,"Invalid tri flag in Atoms section of data file"); + atom->tri[ilocal] = tri_flag; - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(molecule[i]).d; - buf[i][2] = ubuf(type[i]).d; - if (tri[i] < 0) buf[i][3] = ubuf(0).d; - else buf[i][3] = ubuf(1).d; - if (tri[i] < 0) - buf[i][4] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); - else { - MathExtra::sub3(bonus[tri[i]].c2,bonus[tri[i]].c1,c2mc1); - MathExtra::sub3(bonus[tri[i]].c3,bonus[tri[i]].c1,c3mc1); - MathExtra::cross3(c2mc1,c3mc1,norm); - area = 0.5 * MathExtra::len3(norm); - buf[i][4] = rmass[i]/area; - } - buf[i][5] = x[i][0]; - buf[i][6] = x[i][1]; - buf[i][7] = x[i][2]; - buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecTri::pack_data_hybrid(int i, double *buf) -{ - buf[0] = ubuf(molecule[i]).d; - if (tri[i] < 0) buf[1] = ubuf(0).d; - else buf[1] = ubuf(1).d; - if (tri[i] < 0) - buf[2] = rmass[i] / (4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i]); - else { - double c2mc1[3],c3mc1[3],norm[3]; - MathExtra::sub3(bonus[tri[i]].c2,bonus[tri[i]].c1,c2mc1); - MathExtra::sub3(bonus[tri[i]].c3,bonus[tri[i]].c1,c3mc1); - MathExtra::cross3(c2mc1,c3mc1,norm); - double area = 0.5 * MathExtra::len3(norm); - buf[2] = rmass[i]/area; - } - return 3; -} + if (atom->rmass[ilocal] <= 0.0) + error->one(FLERR,"Invalid density in Atoms section of data file"); -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ + if (tri_flag < 0) { + double radius = 0.5; + atom->radius[ilocal] = radius; + atom->rmass[ilocal] *= 4.0*MY_PI/3.0 * radius*radius*radius; + } else atom->radius[ilocal] = 0.0; -void AtomVecTri::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " " TAGINT_FORMAT - " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(tagint) ubuf(buf[i][1]).i, - (int) ubuf(buf[i][2]).i,(int) ubuf(buf[i][3]).i, - buf[i][4],buf[i][5],buf[i][6],buf[i][7], - (int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i, - (int) ubuf(buf[i][10]).i); + atom->omega[ilocal][0] = 0.0; + atom->omega[ilocal][1] = 0.0; + atom->omega[ilocal][2] = 0.0; + atom->angmom[ilocal][0] = 0.0; + atom->angmom[ilocal][1] = 0.0; + atom->angmom[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- - write hybrid atom info to data file + modify values for AtomVec::pack_data() to pack ------------------------------------------------------------------------- */ -int AtomVecTri::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," " TAGINT_FORMAT " %d %-1.16e", - (tagint) ubuf(buf[0]).i,(int) ubuf(buf[1]).i,buf[2]); - return 3; -} +void AtomVecTri::pack_data_pre(int ilocal) +{ + tri_flag = atom->tri[ilocal]; + rmass = atom->rmass[ilocal]; -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ + if (tri_flag < 0) atom->tri[ilocal] = 0; + else atom->tri[ilocal] = 1; -void AtomVecTri::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = omega[i][0]; - buf[i][5] = omega[i][1]; - buf[i][6] = omega[i][2]; - buf[i][7] = angmom[i][0]; - buf[i][8] = angmom[i][1]; - buf[i][9] = angmom[i][2]; + if (tri_flag < 0) { + double radius = atom->radius[ilocal]; + atom->rmass[ilocal] /= 4.0*MY_PI/3.0 * radius*radius*radius; + } else { + double c2mc1[3],c3mc1[3],norm[3]; + MathExtra::sub3(bonus[tri_flag].c2,bonus[tri_flag].c1,c2mc1); + MathExtra::sub3(bonus[tri_flag].c3,bonus[tri_flag].c1,c3mc1); + MathExtra::cross3(c2mc1,c3mc1,norm); + double area = 0.5 * MathExtra::len3(norm); + atom->rmass[ilocal] /= area; } } /* ---------------------------------------------------------------------- - pack hybrid velocity info for data file -------------------------------------------------------------------------- */ - -int AtomVecTri::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = omega[i][0]; - buf[1] = omega[i][1]; - buf[2] = omega[i][2]; - buf[3] = angmom[i][0]; - buf[4] = angmom[i][1]; - buf[5] = angmom[i][2]; - return 6; -} - -/* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ - -void AtomVecTri::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e " - "%-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3], - buf[i][4],buf[i][5],buf[i][6],buf[i][7],buf[i][8],buf[i][9]); -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file + unmodify values packed by AtomVec::pack_data() ------------------------------------------------------------------------- */ -int AtomVecTri::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e", - buf[0],buf[1],buf[2],buf[3],buf[4],buf[5]); - return 6; +void AtomVecTri::pack_data_post(int ilocal) +{ + atom->tri[ilocal] = tri_flag; + atom->rmass[ilocal] = rmass; } /* ---------------------------------------------------------------------- - return # of bytes of allocated memory + set equilateral tri of size in bonus data for particle I + oriented symmetrically in xy plane + this may create or delete entry in bonus data ------------------------------------------------------------------------- */ -bigint AtomVecTri::memory_usage() +void AtomVecTri::set_equilateral(int i, double size) { - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("molecule")) bytes += memory->usage(molecule,nmax); - if (atom->memcheck("rmass")) bytes += memory->usage(rmass,nmax); - if (atom->memcheck("radius")) bytes += memory->usage(radius,nmax); - if (atom->memcheck("omega")) bytes += memory->usage(omega,nmax,3); - if (atom->memcheck("angmom")) bytes += memory->usage(angmom,nmax,3); - if (atom->memcheck("torque")) bytes += - memory->usage(torque,nmax*comm->nthreads,3); - if (atom->memcheck("tri")) bytes += memory->usage(tri,nmax); + // also set radius = distance from center to corner-pt = len(c1) + // unless size = 0.0, then set diameter = 1.0 - bytes += nmax_bonus*sizeof(Bonus); + int *tri = atom->tri; - return bytes; + if (tri[i] < 0) { + if (size == 0.0) return; + if (nlocal_bonus == nmax_bonus) grow_bonus(); + double *quat = bonus[nlocal_bonus].quat; + double *c1 = bonus[nlocal_bonus].c1; + double *c2 = bonus[nlocal_bonus].c2; + double *c3 = bonus[nlocal_bonus].c3; + double *inertia = bonus[nlocal_bonus].inertia; + quat[0] = 1.0; + quat[1] = 0.0; + quat[2] = 0.0; + quat[3] = 0.0; + c1[0] = -size/2.0; + c1[1] = -sqrt(3.0)/2.0 * size / 3.0; + c1[2] = 0.0; + c2[0] = size/2.0; + c2[1] = -sqrt(3.0)/2.0 * size / 3.0; + c2[2] = 0.0; + c3[0] = 0.0; + c3[1] = sqrt(3.0)/2.0 * size * 2.0/3.0; + c3[2] = 0.0; + inertia[0] = sqrt(3.0)/96.0 * size*size*size*size; + inertia[1] = sqrt(3.0)/96.0 * size*size*size*size; + inertia[2] = sqrt(3.0)/48.0 * size*size*size*size; + atom->radius[i] = MathExtra::len3(c1); + bonus[nlocal_bonus].ilocal = i; + tri[i] = nlocal_bonus++; + } else if (size == 0.0) { + atom->radius[i] = 0.5; + copy_bonus_all(nlocal_bonus-1,tri[i]); + nlocal_bonus--; + tri[i] = -1; + } else { + double *c1 = bonus[tri[i]].c1; + double *c2 = bonus[tri[i]].c2; + double *c3 = bonus[tri[i]].c3; + double *inertia = bonus[tri[i]].inertia; + c1[0] = -size/2.0; + c1[1] = -sqrt(3.0)/2.0 * size / 3.0; + c1[2] = 0.0; + c2[0] = size/2.0; + c2[1] = -sqrt(3.0)/2.0 * size / 3.0; + c2[2] = 0.0; + c3[0] = 0.0; + c3[1] = sqrt(3.0)/2.0 * size * 2.0/3.0; + c3[2] = 0.0; + inertia[0] = sqrt(3.0)/96.0 * size*size*size*size; + inertia[1] = sqrt(3.0)/96.0 * size*size*size*size; + inertia[2] = sqrt(3.0)/48.0 * size*size*size*size; + atom->radius[i] = MathExtra::len3(c1); + } } diff --git a/src/atom_vec_tri.h b/src/atom_vec_tri.h index 81b4c1ada9..3c701067b2 100644 --- a/src/atom_vec_tri.h +++ b/src/atom_vec_tri.h @@ -37,49 +37,26 @@ class AtomVecTri : public AtomVec { AtomVecTri(class LAMMPS *); ~AtomVecTri(); void init(); - void grow(int); - void grow_reset(); - void copy(int, int, int); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); - bigint memory_usage(); - - // manipulate Bonus data structure for extra atom info + void copy_bonus(int, int, int); void clear_bonus(); + int pack_comm_bonus(int, int *, double *); + void unpack_comm_bonus(int, int, double *); + int pack_reverse_bonus(int, int, double *); + int pack_border_bonus(int, int *, double *); + int unpack_border_bonus(int, int, double *); + int pack_exchange_bonus(int, double *); + int unpack_exchange_bonus(int, double *); + int size_restart_bonus(); + int pack_restart_bonus(int, double *); + int unpack_restart_bonus(int, double *); void data_atom_bonus(int, char **); + bigint memory_usage_bonus(); + + void create_atom_post(int); + void data_atom_post(int); + void pack_data_pre(int); + void pack_data_post(int); // unique to AtomVecTri @@ -88,19 +65,12 @@ class AtomVecTri : public AtomVec { int nlocal_bonus; private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - tagint *molecule; - double *rmass,*radius; - double **omega,**angmom,**torque; - int *tri; - int nghost_bonus,nmax_bonus; + int tri_flag; + double rmass; void grow_bonus(); - void copy_bonus(int, int); + void copy_bonus_all(int, int); }; } diff --git a/src/read_data.cpp b/src/read_data.cpp index d558b87633..aa4e758744 100644 --- a/src/read_data.cpp +++ b/src/read_data.cpp @@ -568,7 +568,7 @@ void ReadData::command(int narg, char **arg) if (!avec_body) error->all(FLERR,"Invalid data file section: Bodies"); if (atomflag == 0) error->all(FLERR,"Must read Atoms before Bodies"); - bodies(firstpass); + bodies(firstpass,(AtomVec *) avec_body); } else if (strcmp(keyword,"Masses") == 0) { if (firstpass) mass(); @@ -1686,7 +1686,7 @@ void ReadData::bonus(bigint nbonus, AtomVec *ptr, const char *type) if not firstpass, just read past data, but no processing of data ------------------------------------------------------------------------- */ -void ReadData::bodies(int firstpass) +void ReadData::bodies(int firstpass, AtomVec *ptr) { int m,nchunk,nline,nmax,ninteger,ndouble,nword,ncount,onebody,tmp,rv; char *eof; @@ -1770,7 +1770,7 @@ void ReadData::bodies(int firstpass) MPI_Bcast(&m,1,MPI_INT,0,world); MPI_Bcast(buffer,m,MPI_CHAR,0,world); - if (firstpass) atom->data_bodies(nchunk,buffer,avec_body,id_offset); + if (firstpass) atom->data_bodies(nchunk,buffer,ptr,id_offset); nread += nchunk; } diff --git a/src/read_data.h b/src/read_data.h index 98de607f6b..aee54ef3ed 100644 --- a/src/read_data.h +++ b/src/read_data.h @@ -97,7 +97,7 @@ class ReadData : protected Pointers { void impropers(int); void bonus(bigint, class AtomVec *, const char *); - void bodies(int); + void bodies(int, class AtomVec *); void mass(); void paircoeffs(); -- GitLab From ccca80a6a5e5ba9b3d42a5aebaa11552fbd123fe Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Mon, 2 Dec 2019 15:39:54 -0700 Subject: [PATCH 009/577] changes to enable atom_style hybrid to work --- src/DIPOLE/atom_vec_dipole.cpp | 8 +- src/MOLECULE/atom_vec_angle.cpp | 36 +-- src/MOLECULE/atom_vec_bond.cpp | 26 +- src/MOLECULE/atom_vec_full.cpp | 58 ++-- src/MOLECULE/atom_vec_molecular.cpp | 58 ++-- src/MOLECULE/atom_vec_template.cpp | 8 +- src/PERI/atom_vec_peri.cpp | 8 +- src/SPIN/atom_vec_spin.cpp | 6 +- src/USER-DPD/atom_vec_dpd.cpp | 8 +- src/USER-EFF/atom_vec_electron.cpp | 6 +- src/USER-MESO/atom_vec_edpd.cpp | 6 +- src/atom_vec.cpp | 325 +++++++++++---------- src/atom_vec.h | 3 +- src/atom_vec_atomic.cpp | 28 +- src/atom_vec_body.cpp | 8 +- src/atom_vec_body.h | 1 - src/atom_vec_charge.cpp | 14 +- src/atom_vec_ellipsoid.cpp | 8 +- src/atom_vec_ellipsoid.h | 1 - src/atom_vec_hybrid.cpp | 436 +++++++++++++++++++++++++--- src/atom_vec_hybrid.h | 38 ++- src/atom_vec_line.cpp | 8 +- src/atom_vec_line.h | 1 - src/atom_vec_sphere.cpp | 8 +- src/atom_vec_tri.cpp | 8 +- src/atom_vec_tri.h | 1 - 26 files changed, 761 insertions(+), 355 deletions(-) diff --git a/src/DIPOLE/atom_vec_dipole.cpp b/src/DIPOLE/atom_vec_dipole.cpp index 650bc14d8f..5cdbab1b33 100644 --- a/src/DIPOLE/atom_vec_dipole.cpp +++ b/src/DIPOLE/atom_vec_dipole.cpp @@ -35,21 +35,21 @@ AtomVecDipole::AtomVecDipole(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "q mu"; fields_copy = (char *) "q mu"; fields_comm = (char *) "mu3"; fields_comm_vel = (char *) "mu3"; - fields_reverse = NULL; + fields_reverse = (char *) ""; fields_border = (char *) "q mu"; fields_border_vel = (char *) "q mu"; fields_exchange = (char *) "q mu"; fields_restart = (char *) "q mu"; fields_create = (char *) "q mu"; fields_data_atom = (char *) "id type q x mu3"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); } diff --git a/src/MOLECULE/atom_vec_angle.cpp b/src/MOLECULE/atom_vec_angle.cpp index df48c4b2a0..1bd6f9a071 100644 --- a/src/MOLECULE/atom_vec_angle.cpp +++ b/src/MOLECULE/atom_vec_angle.cpp @@ -28,8 +28,8 @@ AtomVecAngle::AtomVecAngle(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "molecule num_bond bond_type bond_atom " @@ -37,9 +37,9 @@ AtomVecAngle::AtomVecAngle(LAMMPS *lmp) : AtomVec(lmp) fields_copy = (char *) "molecule num_bond bond_type bond_atom " "num_angle angle_type angle_atom1 angle_atom2 angle_atom3 nspecial special"; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; fields_border = (char *) "molecule"; fields_border_vel = (char *) "molecule"; fields_exchange = (char *) @@ -50,7 +50,7 @@ AtomVecAngle::AtomVecAngle(LAMMPS *lmp) : AtomVec(lmp) "num_angle angle_type angle_atom1 angle_atom2 angle_atom3"; fields_create = (char *) "molecule num_bond num_angle nspecial"; fields_data_atom = (char *) "id molecule type x"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); @@ -70,7 +70,7 @@ AtomVecAngle::~AtomVecAngle() modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -void AtomVecAngle::pack_restart_pre(int i) +void AtomVecAngle::pack_restart_pre(int ilocal) { // insure negative vectors are needed length @@ -93,19 +93,19 @@ void AtomVecAngle::pack_restart_pre(int i) int **angle_type = atom->angle_type; int any_bond_negative = 0; - for (int m = 0; m < num_bond[i]; m++) { - if (bond_type[i][m] < 0) { + for (int m = 0; m < num_bond[ilocal]; m++) { + if (bond_type[ilocal][m] < 0) { bond_negative[m] = 1; - bond_type[i][m] = -bond_type[i][m]; + bond_type[ilocal][m] = -bond_type[ilocal][m]; any_bond_negative = 1; } else bond_negative[m] = 0; } int any_angle_negative = 0; - for (int m = 0; m < num_angle[i]; m++) { - if (angle_type[i][m] < 0) { + for (int m = 0; m < num_angle[ilocal]; m++) { + if (angle_type[ilocal][m] < 0) { angle_negative[m] = 1; - angle_type[i][m] = -angle_type[i][m]; + angle_type[ilocal][m] = -angle_type[ilocal][m]; any_angle_negative = 1; } else angle_negative[m] = 0; } @@ -115,22 +115,22 @@ void AtomVecAngle::pack_restart_pre(int i) unmodify values packed by AtomVec::pack_restart() ------------------------------------------------------------------------- */ -void AtomVecAngle::pack_restart_post(int i) +void AtomVecAngle::pack_restart_post(int ilocal) { // restore the flagged types to their negative values if (any_bond_negative) { int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; - for (int m = 0; m < num_bond[i]; m++) - if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; + for (int m = 0; m < num_bond[ilocal]; m++) + if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } if (any_angle_negative) { int *num_angle = atom->num_angle; int **angle_type = atom->angle_type; - for (int m = 0; m < num_angle[i]; m++) - if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; + for (int m = 0; m < num_angle[ilocal]; m++) + if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m]; } } diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp index fd3f08979d..30ad7d83e1 100644 --- a/src/MOLECULE/atom_vec_bond.cpp +++ b/src/MOLECULE/atom_vec_bond.cpp @@ -28,16 +28,16 @@ AtomVecBond::AtomVecBond(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "molecule num_bond bond_type bond_atom nspecial special"; fields_copy = (char *) "molecule num_bond bond_type bond_atom nspecial special"; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; fields_border = (char *) "molecule"; fields_border_vel = (char *) "molecule"; fields_exchange = (char *) @@ -45,7 +45,7 @@ AtomVecBond::AtomVecBond(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "molecule num_bond bond_type bond_atom"; fields_create = (char *) "molecule num_bond nspecial"; fields_data_atom = (char *) "id molecule type x"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); @@ -64,7 +64,7 @@ AtomVecBond::~AtomVecBond() modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -void AtomVecBond::pack_restart_pre(int i) +void AtomVecBond::pack_restart_pre(int ilocal) { // insure bond_negative vector is needed length @@ -80,10 +80,10 @@ void AtomVecBond::pack_restart_pre(int i) int **bond_type = atom->bond_type; any_bond_negative = 0; - for (int m = 0; m < num_bond[i]; m++) { - if (bond_type[i][m] < 0) { + for (int m = 0; m < num_bond[ilocal]; m++) { + if (bond_type[ilocal][m] < 0) { bond_negative[m] = 1; - bond_type[i][m] = -bond_type[i][m]; + bond_type[ilocal][m] = -bond_type[ilocal][m]; any_bond_negative = 1; } else bond_negative[m] = 0; } @@ -93,15 +93,15 @@ void AtomVecBond::pack_restart_pre(int i) unmodify values packed by AtomVec::pack_restart() ------------------------------------------------------------------------- */ -void AtomVecBond::pack_restart_post(int i) +void AtomVecBond::pack_restart_post(int ilocal) { // restore the flagged types to their negative values if (any_bond_negative) { int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; - for (int m = 0; m < num_bond[i]; m++) - if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; + for (int m = 0; m < num_bond[ilocal]; m++) + if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } } diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp index ed838aa0e3..9ab0a296e0 100644 --- a/src/MOLECULE/atom_vec_full.cpp +++ b/src/MOLECULE/atom_vec_full.cpp @@ -28,8 +28,8 @@ AtomVecFull::AtomVecFull(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "q molecule num_bond bond_type bond_atom " @@ -47,9 +47,9 @@ AtomVecFull::AtomVecFull(LAMMPS *lmp) : AtomVec(lmp) "num_improper improper_type improper_atom1 improper_atom2 " "improper_atom3 improper_atom4 " "nspecial special"; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; fields_border = (char *) "q molecule"; fields_border_vel = (char *) "q molecule"; fields_exchange = (char *) @@ -70,7 +70,7 @@ AtomVecFull::AtomVecFull(LAMMPS *lmp) : AtomVec(lmp) fields_create = (char *) "q molecule num_bond num_angle num_dihedral num_improper nspecial"; fields_data_atom = (char *) "id molecule type q x"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); @@ -92,7 +92,7 @@ AtomVecFull::~AtomVecFull() modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -void AtomVecFull::pack_restart_pre(int i) +void AtomVecFull::pack_restart_pre(int ilocal) { // insure negative vectors are needed length @@ -129,37 +129,37 @@ void AtomVecFull::pack_restart_pre(int i) int **improper_type = atom->improper_type; int any_bond_negative = 0; - for (int m = 0; m < num_bond[i]; m++) { - if (bond_type[i][m] < 0) { + for (int m = 0; m < num_bond[ilocal]; m++) { + if (bond_type[ilocal][m] < 0) { bond_negative[m] = 1; - bond_type[i][m] = -bond_type[i][m]; + bond_type[ilocal][m] = -bond_type[ilocal][m]; any_bond_negative = 1; } else bond_negative[m] = 0; } int any_angle_negative = 0; - for (int m = 0; m < num_angle[i]; m++) { - if (angle_type[i][m] < 0) { + for (int m = 0; m < num_angle[ilocal]; m++) { + if (angle_type[ilocal][m] < 0) { angle_negative[m] = 1; - angle_type[i][m] = -angle_type[i][m]; + angle_type[ilocal][m] = -angle_type[ilocal][m]; any_angle_negative = 1; } else angle_negative[m] = 0; } int any_dihedral_negative = 0; - for (int m = 0; m < num_dihedral[i]; m++) { - if (dihedral_type[i][m] < 0) { + for (int m = 0; m < num_dihedral[ilocal]; m++) { + if (dihedral_type[ilocal][m] < 0) { dihedral_negative[m] = 1; - dihedral_type[i][m] = -dihedral_type[i][m]; + dihedral_type[ilocal][m] = -dihedral_type[ilocal][m]; any_dihedral_negative = 1; } else dihedral_negative[m] = 0; } int any_improper_negative = 0; - for (int m = 0; m < num_improper[i]; m++) { - if (improper_type[i][m] < 0) { + for (int m = 0; m < num_improper[ilocal]; m++) { + if (improper_type[ilocal][m] < 0) { improper_negative[m] = 1; - improper_type[i][m] = -improper_type[i][m]; + improper_type[ilocal][m] = -improper_type[ilocal][m]; any_improper_negative = 1; } else improper_negative[m] = 0; } @@ -169,36 +169,38 @@ void AtomVecFull::pack_restart_pre(int i) unmodify values packed by AtomVec::pack_restart() ------------------------------------------------------------------------- */ -void AtomVecFull::pack_restart_post(int i) +void AtomVecFull::pack_restart_post(int ilocal) { // restore the flagged types to their negative values if (any_bond_negative) { int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; - for (int m = 0; m < num_bond[i]; m++) - if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; + for (int m = 0; m < num_bond[ilocal]; m++) + if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } if (any_angle_negative) { int *num_angle = atom->num_angle; int **angle_type = atom->angle_type; - for (int m = 0; m < num_angle[i]; m++) - if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; + for (int m = 0; m < num_angle[ilocal]; m++) + if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m]; } if (any_dihedral_negative) { int *num_dihedral = atom->num_dihedral; int **dihedral_type = atom->dihedral_type; - for (int m = 0; m < num_dihedral[i]; m++) - if (dihedral_negative[m]) dihedral_type[i][m] = -dihedral_type[i][m]; + for (int m = 0; m < num_dihedral[ilocal]; m++) + if (dihedral_negative[m]) + dihedral_type[ilocal][m] = -dihedral_type[ilocal][m]; } if (any_improper_negative) { int *num_improper = atom->num_improper; int **improper_type = atom->improper_type; - for (int m = 0; m < num_improper[i]; m++) - if (improper_negative[m]) improper_type[i][m] = -improper_type[i][m]; + for (int m = 0; m < num_improper[ilocal]; m++) + if (improper_negative[m]) + improper_type[ilocal][m] = -improper_type[ilocal][m]; } } diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp index 77aec2cf50..52947ceb71 100644 --- a/src/MOLECULE/atom_vec_molecular.cpp +++ b/src/MOLECULE/atom_vec_molecular.cpp @@ -28,8 +28,8 @@ AtomVecMolecular::AtomVecMolecular(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "molecule num_bond bond_type bond_atom " @@ -47,9 +47,9 @@ AtomVecMolecular::AtomVecMolecular(LAMMPS *lmp) : AtomVec(lmp) "num_improper improper_type improper_atom1 improper_atom2 " "improper_atom3 improper_atom4 " "nspecial special"; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; fields_border = (char *) "molecule"; fields_border_vel = (char *) "molecule"; fields_exchange = (char *) @@ -70,7 +70,7 @@ AtomVecMolecular::AtomVecMolecular(LAMMPS *lmp) : AtomVec(lmp) fields_create = (char *) "molecule num_bond num_angle num_dihedral num_improper nspecial"; fields_data_atom = (char *) "id molecule type x"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); @@ -92,7 +92,7 @@ AtomVecMolecular::~AtomVecMolecular() modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ -void AtomVecMolecular::pack_restart_pre(int i) +void AtomVecMolecular::pack_restart_pre(int ilocal) { // insure negative vectors are needed length @@ -129,37 +129,37 @@ void AtomVecMolecular::pack_restart_pre(int i) int **improper_type = atom->improper_type; int any_bond_negative = 0; - for (int m = 0; m < num_bond[i]; m++) { - if (bond_type[i][m] < 0) { + for (int m = 0; m < num_bond[ilocal]; m++) { + if (bond_type[ilocal][m] < 0) { bond_negative[m] = 1; - bond_type[i][m] = -bond_type[i][m]; + bond_type[ilocal][m] = -bond_type[ilocal][m]; any_bond_negative = 1; } else bond_negative[m] = 0; } int any_angle_negative = 0; - for (int m = 0; m < num_angle[i]; m++) { - if (angle_type[i][m] < 0) { + for (int m = 0; m < num_angle[ilocal]; m++) { + if (angle_type[ilocal][m] < 0) { angle_negative[m] = 1; - angle_type[i][m] = -angle_type[i][m]; + angle_type[ilocal][m] = -angle_type[ilocal][m]; any_angle_negative = 1; } else angle_negative[m] = 0; } int any_dihedral_negative = 0; - for (int m = 0; m < num_dihedral[i]; m++) { - if (dihedral_type[i][m] < 0) { + for (int m = 0; m < num_dihedral[ilocal]; m++) { + if (dihedral_type[ilocal][m] < 0) { dihedral_negative[m] = 1; - dihedral_type[i][m] = -dihedral_type[i][m]; + dihedral_type[ilocal][m] = -dihedral_type[ilocal][m]; any_dihedral_negative = 1; } else dihedral_negative[m] = 0; } int any_improper_negative = 0; - for (int m = 0; m < num_improper[i]; m++) { - if (improper_type[i][m] < 0) { + for (int m = 0; m < num_improper[ilocal]; m++) { + if (improper_type[ilocal][m] < 0) { improper_negative[m] = 1; - improper_type[i][m] = -improper_type[i][m]; + improper_type[ilocal][m] = -improper_type[ilocal][m]; any_improper_negative = 1; } else improper_negative[m] = 0; } @@ -169,36 +169,38 @@ void AtomVecMolecular::pack_restart_pre(int i) unmodify values packed by AtomVec::pack_restart() ------------------------------------------------------------------------- */ -void AtomVecMolecular::pack_restart_post(int i) +void AtomVecMolecular::pack_restart_post(int ilocal) { // restore the flagged types to their negative values if (any_bond_negative) { int *num_bond = atom->num_bond; int **bond_type = atom->bond_type; - for (int m = 0; m < num_bond[i]; m++) - if (bond_negative[m]) bond_type[i][m] = -bond_type[i][m]; + for (int m = 0; m < num_bond[ilocal]; m++) + if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } if (any_angle_negative) { int *num_angle = atom->num_angle; int **angle_type = atom->angle_type; - for (int m = 0; m < num_angle[i]; m++) - if (angle_negative[m]) angle_type[i][m] = -angle_type[i][m]; + for (int m = 0; m < num_angle[ilocal]; m++) + if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m]; } if (any_dihedral_negative) { int *num_dihedral = atom->num_dihedral; int **dihedral_type = atom->dihedral_type; - for (int m = 0; m < num_dihedral[i]; m++) - if (dihedral_negative[m]) dihedral_type[i][m] = -dihedral_type[i][m]; + for (int m = 0; m < num_dihedral[ilocal]; m++) + if (dihedral_negative[m]) + dihedral_type[ilocal][m] = -dihedral_type[ilocal][m]; } if (any_improper_negative) { int *num_improper = atom->num_improper; int **improper_type = atom->improper_type; - for (int m = 0; m < num_improper[i]; m++) - if (improper_negative[m]) improper_type[i][m] = -improper_type[i][m]; + for (int m = 0; m < num_improper[ilocal]; m++) + if (improper_negative[m]) + improper_type[ilocal][m] = -improper_type[ilocal][m]; } } diff --git a/src/MOLECULE/atom_vec_template.cpp b/src/MOLECULE/atom_vec_template.cpp index f8f99ae8a8..546c19da12 100644 --- a/src/MOLECULE/atom_vec_template.cpp +++ b/src/MOLECULE/atom_vec_template.cpp @@ -40,16 +40,16 @@ AtomVecTemplate::AtomVecTemplate(LAMMPS *lmp) : AtomVec(lmp) fields_grow = (char *) "molecule molindex molatom"; fields_copy = (char *) "molecule molindex molatom"; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; fields_border = (char *) "molecule molindex molatom"; fields_border_vel = (char *) "molecule molindex molatom"; fields_exchange = (char *) "molecule molindex molatom"; fields_restart = (char *) "molecule molindex molatom"; fields_create = (char *) "molecule molindex molatom"; fields_data_atom = (char *) "id molecule molindex molatom type x"; - fields_data_vel = NULL; + fields_data_vel = (char *) ""; setup_fields(); } diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp index 4fcebc2f84..58ff9c54d9 100644 --- a/src/PERI/atom_vec_peri.cpp +++ b/src/PERI/atom_vec_peri.cpp @@ -50,21 +50,21 @@ AtomVecPeri::AtomVecPeri(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "rmass vfrac s0 x0"; fields_copy = (char *) "rmass vfrac s0 x0"; fields_comm = (char *) "s0"; fields_comm_vel = (char *) "s0"; - fields_reverse = NULL; + fields_reverse = (char *) ""; fields_border = (char *) "rmass vfrac s0 x0"; fields_border_vel = (char *) "rmass vfrac s0 x0"; fields_exchange = (char *) "rmass vfrac s0 x0"; fields_restart = (char *) "rmass vfrac s0 x0"; fields_create = (char *) "rmass vfrac s0 x0"; fields_data_atom = (char *) "id type vfrac rmass x"; - fields_data_vel = (char *) "omega"; + fields_data_vel = (char *) "id v omega"; setup_fields(); } diff --git a/src/SPIN/atom_vec_spin.cpp b/src/SPIN/atom_vec_spin.cpp index 6c88fb1a9e..a8ff15492a 100644 --- a/src/SPIN/atom_vec_spin.cpp +++ b/src/SPIN/atom_vec_spin.cpp @@ -42,8 +42,8 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "sp fm fm_long"; fields_copy = (char *) "sp"; @@ -56,7 +56,7 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "sp"; fields_create = (char *) "sp"; fields_data_atom = (char *) "id type x sp"; - fields_data_vel = (char *) "omega"; + fields_data_vel = (char *) "id v omega"; setup_fields(); } diff --git a/src/USER-DPD/atom_vec_dpd.cpp b/src/USER-DPD/atom_vec_dpd.cpp index 27e0f70a20..ce35178d8d 100644 --- a/src/USER-DPD/atom_vec_dpd.cpp +++ b/src/USER-DPD/atom_vec_dpd.cpp @@ -33,21 +33,21 @@ AtomVecDPD::AtomVecDPD(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "rho dpdTheta uCond uMech uChem uCG uCGnew duChem"; fields_copy = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; fields_comm = (char *) "dpdTheta uCond uMech uChem"; fields_comm_vel = (char *) "dpdTheta uCond uMech uChem"; - fields_reverse = NULL; + fields_reverse = (char *) ""; fields_border = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; fields_border_vel = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; fields_exchange = (char *) "dpdTheta uCond uMech uChem uCG uCGnew"; fields_restart = (char *) "dpdTheta uCond uMech uChem"; fields_create = (char *) "rho dpdTheta uCond uMech uChem uCG uCGnew duChem"; fields_data_atom = (char *) "id type dpdTheta x"; - fields_data_vel = (char *) "omega"; + fields_data_vel = (char *) "id v omega"; setup_fields(); } diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp index fc73bf4dd5..0bad0f115f 100644 --- a/src/USER-EFF/atom_vec_electron.cpp +++ b/src/USER-EFF/atom_vec_electron.cpp @@ -56,8 +56,8 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "q spin eradius ervel erforce"; fields_copy = (char *) "q spin eradius ervel"; @@ -70,7 +70,7 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "q spin eradius ervel"; fields_create = (char *) "q spin eradius ervel"; fields_data_atom = (char *) "id type q spin eradius x"; - fields_data_vel = (char *) "ervel"; + fields_data_vel = (char *) "id v ervel"; setup_fields(); } diff --git a/src/USER-MESO/atom_vec_edpd.cpp b/src/USER-MESO/atom_vec_edpd.cpp index 59cee397b5..b4602c760c 100644 --- a/src/USER-MESO/atom_vec_edpd.cpp +++ b/src/USER-MESO/atom_vec_edpd.cpp @@ -41,8 +41,8 @@ AtomVecEDPD::AtomVecEDPD(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "edpd_cv edpd_temp edpd_flux vest"; fields_copy = (char *) "edpd_cv edpd_temp edpd_flux vest"; @@ -55,7 +55,7 @@ AtomVecEDPD::AtomVecEDPD(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char * ) "edpd_cv edpd_temp vest"; fields_create = (char *) "edpd_cv edpd_temp edpd_flux vest"; fields_data_atom = (char *) "id type edpd_temp edpd_cv x"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); } diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index ed56151d33..cfbc8b12a6 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -55,20 +55,19 @@ AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp) // peratom variables auto-included in corresponding child style fields string // these fields cannot be specified in the fields string - // leading/trailing whitespace just facilitates matching in process_args() - - default_grow = " id type mask image x v f "; - default_copy = " id type mask image x v "; - default_comm = " x "; - default_comm_vel = " x v "; - default_reverse = " f "; - default_border = " id type mask x "; - default_border_vel = " id type mask x v "; - default_exchange = " id type mask image x v "; - default_restart = " id type mask image x v "; - default_create = " id type mask image x v "; + + default_grow = "id type mask image x v f"; + default_copy = "id type mask image x v"; + default_comm = "x"; + default_comm_vel = "x v"; + default_reverse = "f"; + default_border = "id type mask x"; + default_border_vel = "id type mask x v"; + default_exchange = "id type mask image x v"; + default_restart = "id type mask image x v"; + default_create = "id type mask image x v"; default_data_atom = ""; - default_data_vel = " v "; + default_data_vel = ""; // initializations @@ -1757,6 +1756,7 @@ void AtomVec::pack_data(double **buf) void *pdata; int nlocal = atom->nlocal; + for (int i = 0; i < nlocal; i++) { // if needed, change values before packing @@ -1877,37 +1877,39 @@ void AtomVec::data_vel(int ilocal, char **values) v[ilocal][1] = utils::numeric(FLERR,values[1],true,lmp); v[ilocal][2] = utils::numeric(FLERR,values[2],true,lmp); - int ivalue = 3; - for (n = 0; n < ndata_vel; n++) { - pdata = mdata_vel.pdata[n]; - datatype = mdata_vel.datatype[n]; - cols = mdata_vel.cols[n]; - if (datatype == DOUBLE) { - if (cols == 0) { - double *vec = *((double **) pdata); - vec[ilocal] = utils::numeric(FLERR,values[ivalue++],true,lmp); - } else { - double **array = *((double ***) pdata); - for (m = 0; m < cols; m++) - array[ilocal][m] = utils::numeric(FLERR,values[ivalue++],true,lmp); - } - } else if (datatype == INT) { - if (cols == 0) { - int *vec = *((int **) pdata); - vec[ilocal] = utils::inumeric(FLERR,values[ivalue++],true,lmp); - } else { - int **array = *((int ***) pdata); - for (m = 0; m < cols; m++) - array[ilocal][m] = utils::inumeric(FLERR,values[ivalue++],true,lmp); - } - } else if (datatype == BIGINT) { - if (cols == 0) { - bigint *vec = *((bigint **) pdata); - vec[ilocal] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); - } else { - bigint **array = *((bigint ***) pdata); - for (m = 0; m < cols; m++) - array[ilocal][m] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + if (ndata_vel) { + int ivalue = 3; + for (n = 0; n < ndata_vel; n++) { + pdata = mdata_vel.pdata[n]; + datatype = mdata_vel.datatype[n]; + cols = mdata_vel.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + vec[ilocal] = utils::numeric(FLERR,values[ivalue++],true,lmp); + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + array[ilocal][m] = utils::numeric(FLERR,values[ivalue++],true,lmp); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + vec[ilocal] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + array[ilocal][m] = utils::inumeric(FLERR,values[ivalue++],true,lmp); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + vec[ilocal] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + array[ilocal][m] = utils::bnumeric(FLERR,values[ivalue++],true,lmp); + } } } } @@ -1922,49 +1924,40 @@ void AtomVec::pack_vel(double **buf) int i,j,m,n,datatype,cols; void *pdata; - double **v = atom->v; - tagint *tag = atom->tag; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - - j = 4; - if (ndata_vel) { - for (n = 0; n < ndata_vel; n++) { - pdata = mdata_vel.pdata[n]; - datatype = mdata_vel.datatype[n]; - cols = mdata_vel.cols[n]; - if (datatype == DOUBLE) { - if (cols == 0) { - double *vec = *((double **) pdata); - buf[i][j++] = vec[i]; - } else { - double **array = *((double ***) pdata); - for (m = 0; m < cols; m++) - buf[i][j++] = array[i][m]; - } - } else if (datatype == INT) { - if (cols == 0) { - int *vec = *((int **) pdata); - buf[i][j++] = ubuf(vec[i]).d; - } else { - int **array = *((int ***) pdata); - for (m = 0; m < cols; m++) - buf[i][j++] = ubuf(array[i][m]).d; - } - } else if (datatype == BIGINT) { - if (cols == 0) { - bigint *vec = *((bigint **) pdata); - buf[i][j++] = ubuf(vec[i]).d; - } else { - bigint **array = *((bigint ***) pdata); - for (m = 0; m < cols; m++) - buf[i][j++] = ubuf(array[i][m]).d; - } + j = 0; + for (n = 0; n < ndata_vel; n++) { + pdata = mdata_vel.pdata[n]; + datatype = mdata_vel.datatype[n]; + cols = mdata_vel.cols[n]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + buf[i][j++] = vec[i]; + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = array[i][m]; + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + buf[i][j++] = ubuf(vec[i]).d; + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = ubuf(array[i][m]).d; + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + buf[i][j++] = ubuf(vec[i]).d; + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + buf[i][j++] = ubuf(array[i][m]).d; } } } @@ -1985,37 +1978,39 @@ void AtomVec::write_vel(FILE *fp, int n, double **buf) fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e\n", (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]); - j = 4; - for (nn = 0; nn < ndata_vel; nn++) { - pdata = mdata_vel.pdata[nn]; - datatype = mdata_vel.datatype[nn]; - cols = mdata_vel.cols[nn]; - if (datatype == DOUBLE) { - if (cols == 0) { - double *vec = *((double **) pdata); - fprintf(fp," %-1.16e",buf[i][j++]); - } else { - double **array = *((double ***) pdata); - for (m = 0; m < cols; m++) + if (ndata_vel) { + j = 4; + for (nn = 0; nn < ndata_vel; nn++) { + pdata = mdata_vel.pdata[nn]; + datatype = mdata_vel.datatype[nn]; + cols = mdata_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); fprintf(fp," %-1.16e",buf[i][j++]); - } - } else if (datatype == INT) { - if (cols == 0) { - int *vec = *((int **) pdata); - fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); - } else { - int **array = *((int ***) pdata); - for (m = 0; m < cols; m++) + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," %-1.16e",buf[i][j++]); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); - } - } else if (datatype == BIGINT) { - if (cols == 0) { - bigint *vec = *((bigint **) pdata); - fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); - } else { - bigint **array = *((bigint ***) pdata); - for (m = 0; m < cols; m++) + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) + fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } } } } @@ -2342,10 +2337,11 @@ void AtomVec::setup_fields() { int n,cols; - if (!fields_data_atom) - error->all(FLERR,"Atom style requires fields_data_atom"); if (strstr(fields_data_atom,"id ") != fields_data_atom) error->all(FLERR,"Atom style fields_data_atom must have id as first field"); + if (strstr(fields_data_vel,"id v") != fields_data_vel) + error->all(FLERR,"Atom style fields_data_vel must have " + "'id v' as first fields"); // process field strings // return # of fields and matching index into atom->peratom (in Method struct) @@ -2387,7 +2383,7 @@ void AtomVec::setup_fields() else threads[i] = 1; } - // set style-specific variables + // set style-specific sizes // NOTE: check for others vars in atom_vec.cpp/h ?? // NOTE: need to set maxexchange, e.g for style hybrid? @@ -2437,7 +2433,7 @@ void AtomVec::setup_fields() else size_data_atom += cols; } - size_data_vel = 4; + size_data_vel = 0; for (n = 0; n < ndata_vel; n++) { cols = mdata_vel.cols[n]; if (cols == 0) size_data_vel++; @@ -2449,61 +2445,96 @@ void AtomVec::setup_fields() process a single field string ------------------------------------------------------------------------- */ -int AtomVec::process_fields(char *list, const char *default_list, Method *method) +int AtomVec::process_fields(char *str, const char *default_str, Method *method) { - int i,n; - char match[128]; - - if (list == NULL) { + if (str == NULL) { method->index = NULL; return 0; } - // make copy of list of fields so can tokenize it - - n = strlen(list) + 1; - char *copy = new char[n]; - strcpy(copy,list); + // tokenize words in both strings - int nfield = atom->count_words(copy); - int *index = new int[nfield]; + char *copy1,*copy2; + char **words,**defwords; + int nfield = tokenize(str,words,copy1); + int ndef = tokenize((char *) default_str,defwords,copy2); + // process fields one by one, add to index vector + Atom::PerAtom *peratom = atom->peratom; int nperatom = atom->nperatom; - - nfield = 0; - char *field = strtok(copy," "); - while (field) { + + int *index = new int[nfield]; + int match; + + for (int i = 0; i < nfield; i++) { // find field in master Atom::peratom list - for (i = 0; i < nperatom; i++) - if (strcmp(field,peratom[i].name) == 0) break; - if (i == nperatom) { - printf("FIELD %s\n",field); - error->all(FLERR,"Atom_style unrecognized peratom field"); + for (match = 0; match < nperatom; match++) + if (strcmp(words[i],peratom[match].name) == 0) break; + if (match == nperatom) { + char str[128]; + sprintf(str,"Peratom field %s not recognized",words[i]); + error->all(FLERR,str); } - index[nfield++] = i; + index[i] = match; + + // error if field appears multiple times - // error if field is in default list or appears multiple times + for (match = 0; match < i; match++) + if (index[i] == index[match]) { + char str[128]; + sprintf(str,"Peratom field %s is repeated",words[i]); + error->all(FLERR,str); + } - sprintf(match," %s ",field); - if (strstr(default_list,match)) - error->all(FLERR,"Atom_style repeat of default peratom field"); + // error if field is in default str - for (i = 0; i < nfield-1; i++) - if (index[i] == index[nfield-1]) - error->all(FLERR,"Atom_style duplicated peratom field"); + for (match = 0; match < ndef; match++) + if (strcmp(words[i],defwords[match]) == 0) { + char str[128]; + sprintf(str,"Peratom field %s is a default",words[i]); + error->all(FLERR,str); + } - field = strtok(NULL," "); } - delete [] copy; + delete [] copy1; + delete [] copy2; + delete [] words; + delete [] defwords; method->index = index; return nfield; } +/* ---------------------------------------------------------------------- + tokenize str into white-space separated words + return nwords = number of words + return words = vector of ptrs to each word + also return copystr since words points into it, caller will delete copystr +------------------------------------------------------------------------- */ + +int AtomVec::tokenize(char *str, char **&words, char *©str) +{ + int n = strlen(str) + 1; + copystr = new char[n]; + strcpy(copystr,str); + + int nword = atom->count_words(copystr); + words = new char*[nword]; + + nword = 0; + char *word = strtok(copystr," "); + while (word) { + words[nword++] = word; + word = strtok(NULL," "); + } + + return nword; +} + /* ---------------------------------------------------------------------- create a method data structs for processing fields ------------------------------------------------------------------------- */ diff --git a/src/atom_vec.h b/src/atom_vec.h index 33bf4a3ccd..69ea1d51ab 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -55,7 +55,7 @@ class AtomVec : protected Pointers { char **argcopy; // used when AtomVec is realloced (restart,replicate) // additional list of peratom fields operated on by different methods - // set by child styles + // set or created by child styles char *fields_grow,*fields_copy; char *fields_comm,*fields_comm_vel,*fields_reverse; @@ -220,6 +220,7 @@ class AtomVec : protected Pointers { int grow_nmax_bonus(int); void setup_fields(); int process_fields(char *, const char *, Method *); + int tokenize(char *, char **&, char *&); void create_method(int, Method *); void init_method(Method *); void destroy_method(Method *); diff --git a/src/atom_vec_atomic.cpp b/src/atom_vec_atomic.cpp index a283e99081..eb8dfc1b7e 100644 --- a/src/atom_vec_atomic.cpp +++ b/src/atom_vec_atomic.cpp @@ -24,21 +24,21 @@ AtomVecAtomic::AtomVecAtomic(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file - - fields_grow = NULL; - fields_copy = NULL; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; - fields_border = NULL; - fields_border_vel = NULL; - fields_exchange = NULL; - fields_restart = NULL; - fields_create = NULL; + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file + + fields_grow = (char *) ""; + fields_copy = (char *) ""; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; + fields_border = (char *) ""; + fields_border_vel = (char *) ""; + fields_exchange = (char *) ""; + fields_restart = (char *) ""; + fields_create = (char *) ""; fields_data_atom = (char *) "id type x"; - fields_data_vel = NULL; + fields_data_vel = (char *) "id v"; setup_fields(); } diff --git a/src/atom_vec_body.cpp b/src/atom_vec_body.cpp index 1a8c2defd9..19ac69cef3 100644 --- a/src/atom_vec_body.cpp +++ b/src/atom_vec_body.cpp @@ -60,12 +60,12 @@ AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "radius rmass angmom torque body"; fields_copy = (char *) "radius rmass angmom"; - fields_comm = NULL; + fields_comm = (char *) ""; fields_comm_vel = (char *) "angmom"; fields_reverse = (char *) "torque"; fields_border = (char *) "radius rmass"; @@ -74,7 +74,7 @@ AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "radius rmass angmom"; fields_create = (char *) "radius rmass angmom tri"; fields_data_atom = (char *) "id type body rmass x"; - fields_data_vel = (char *) "angmom"; + fields_data_vel = (char *) "id v angmom"; setup_fields(); } diff --git a/src/atom_vec_body.h b/src/atom_vec_body.h index 183b4ea8ea..939b01878d 100644 --- a/src/atom_vec_body.h +++ b/src/atom_vec_body.h @@ -47,7 +47,6 @@ class AtomVecBody : public AtomVec { void clear_bonus(); int pack_comm_bonus(int, int *, double *); void unpack_comm_bonus(int, int, double *); - int pack_reverse_bonus(int, int, double *); int pack_border_bonus(int, int *, double *); int unpack_border_bonus(int, int, double *); int pack_exchange_bonus(int, double *); diff --git a/src/atom_vec_charge.cpp b/src/atom_vec_charge.cpp index 9c8f18a846..5957ef5215 100644 --- a/src/atom_vec_charge.cpp +++ b/src/atom_vec_charge.cpp @@ -27,21 +27,21 @@ AtomVecCharge::AtomVecCharge(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "q"; fields_copy = (char *) "q"; - fields_comm = NULL; - fields_comm_vel = NULL; - fields_reverse = NULL; + fields_comm = (char *) ""; + fields_comm_vel = (char *) ""; + fields_reverse = (char *) ""; fields_border = (char *) "q"; fields_border_vel = (char *) "q"; fields_exchange = (char *) "q"; fields_restart = (char *) "q"; fields_create = (char *) "q"; - fields_data_atom = (char *) "id type q x"; - fields_data_vel = NULL; + fields_data_atom = (char *) "id type q x"; + fields_data_vel = (char *) "id v"; setup_fields(); } diff --git a/src/atom_vec_ellipsoid.cpp b/src/atom_vec_ellipsoid.cpp index 7ba26c1c34..9166293384 100644 --- a/src/atom_vec_ellipsoid.cpp +++ b/src/atom_vec_ellipsoid.cpp @@ -49,12 +49,12 @@ AtomVecEllipsoid::AtomVecEllipsoid(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "rmass angmom torque ellipsoid"; fields_copy = (char *) "rmass angmom"; - fields_comm = NULL; + fields_comm = (char *) ""; fields_comm_vel = (char *) "angmom"; fields_reverse = (char *) "torque"; fields_border = (char *) "rmass"; @@ -63,7 +63,7 @@ AtomVecEllipsoid::AtomVecEllipsoid(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "rmass angmom"; fields_create = (char *) "rmass angmom ellipsoid"; fields_data_atom = (char *) "id type ellipsoid rmass x"; - fields_data_vel = (char *) "angmom"; + fields_data_vel = (char *) "id v angmom"; setup_fields(); } diff --git a/src/atom_vec_ellipsoid.h b/src/atom_vec_ellipsoid.h index 70797c59d5..79d17a2206 100644 --- a/src/atom_vec_ellipsoid.h +++ b/src/atom_vec_ellipsoid.h @@ -40,7 +40,6 @@ class AtomVecEllipsoid : public AtomVec { void clear_bonus(); int pack_comm_bonus(int, int *, double *); void unpack_comm_bonus(int, int, double *); - int pack_reverse_bonus(int, int, double *); int pack_border_bonus(int, int *, double *); int unpack_border_bonus(int, int, double *); int pack_exchange_bonus(int, double *); diff --git a/src/atom_vec_hybrid.cpp b/src/atom_vec_hybrid.cpp index d96494544c..9a79f66972 100644 --- a/src/atom_vec_hybrid.cpp +++ b/src/atom_vec_hybrid.cpp @@ -14,18 +14,39 @@ #include "atom_vec_hybrid.h" #include #include "atom.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" +#include "comm.h" #include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; +#define NFIELDSTRINGS 12 // # of field strings + /* ---------------------------------------------------------------------- */ -AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp) : AtomVec(lmp) {} +AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp) : AtomVec(lmp) +{ + nstyles = 0; + styles = NULL; + keywords = NULL; + fieldstrings = NULL; + + nstyles_bonus = 0; + styles_bonus = NULL; + + // NOTE: set bonus_flag if any substyle does + // set nstyles_bonus, styles_bonus + // NOTE: call method in each sub-style to set q_flag ?? + + // these strings will be concatenated from sub-style strings + // fields_data_atom & fields_data_vel start with fields common to all styles + + fields_grow = fields_copy = fields_comm = fields_comm_vel = (char *) ""; + fields_reverse = fields_border = fields_border_vel = (char *) ""; + fields_exchange = fields_restart = fields_create = (char *) ""; + fields_data_atom = (char *) "id type x"; + fields_data_vel = (char *) "id v"; +} /* ---------------------------------------------------------------------- */ @@ -36,14 +57,23 @@ AtomVecHybrid::~AtomVecHybrid() for (int k = 0; k < nstyles; k++) delete [] keywords[k]; delete [] keywords; - // these strings will be concatenated from sub-style strings - // fields_data_atom must start with fields common to all styles - - fields_grow = fields_copy = fields_comm = fields_comm_vel = NULL; - fields_reverse = fields_border = fields_border_vel = NULL; - fields_exchange = fields_restart = fields_create = NULL; - fields_data_atom = (char *) "id type x"; - fields_data_vel = NULL; + // NOTE: need to check these have actually been allocated + + delete [] fields_grow; + delete [] fields_copy; + delete [] fields_comm; + delete [] fields_comm_vel; + delete [] fields_reverse; + delete [] fields_border; + delete [] fields_border_vel; + delete [] fields_exchange; + delete [] fields_restart; + delete [] fields_create; + delete [] fields_data_atom; + delete [] fields_data_vel; + + for (int k = 0; k < nstyles; k++) delete [] fieldstrings[k].fstr; + delete [] fieldstrings; } /* ---------------------------------------------------------------------- @@ -52,7 +82,7 @@ AtomVecHybrid::~AtomVecHybrid() void AtomVecHybrid::process_args(int narg, char **arg) { - // build list of all known atom styles + // create list of all known atom styles build_styles(); @@ -85,70 +115,311 @@ void AtomVecHybrid::process_args(int narg, char **arg) nstyles++; } + // hybrid settings are MAX or MIN of sub-style settings + // check for both mass_type = 0 and 1, so can warn + + molecular = 0; + maxexchange = 0; + + for (int k = 0; k < nstyles; k++) { + if ((styles[k]->molecular == 1 && molecular == 2) || + (styles[k]->molecular == 2 && molecular == 1)) + error->all(FLERR,"Cannot mix molecular and molecule template " + "atom styles"); + molecular = MAX(molecular,styles[k]->molecular); + + bonds_allow = MAX(bonds_allow,styles[k]->bonds_allow); + angles_allow = MAX(angles_allow,styles[k]->angles_allow); + dihedrals_allow = MAX(dihedrals_allow,styles[k]->dihedrals_allow); + impropers_allow = MAX(impropers_allow,styles[k]->impropers_allow); + mass_type = MAX(mass_type,styles[k]->mass_type); + dipole_type = MAX(dipole_type,styles[k]->dipole_type); + forceclearflag = MAX(forceclearflag,styles[k]->forceclearflag); + + if (styles[k]->molecular == 2) onemols = styles[k]->onemols; + + // NOTE: need to sum this one? + maxexchange += styles[k]->maxexchange; + } + + // issue a warning if both per-type mass and per-atom rmass are defined + + int mass_pertype = 0; + int mass_peratom = 0; + + for (int k = 0; k < nstyles; k++) { + if (styles[k]->mass_type == 0) mass_peratom = 1; + if (styles[k]->mass_type == 1) mass_pertype = 1; + } + + if (mass_pertype && mass_peratom && comm->me == 0) + error->warning(FLERR, + "Atom_style hybrid defines both pertype and peratom masses " + "- both must be set, only peratom masses will be used"); + // free allstyles created by build_styles() for (int i = 0; i < nallstyles; i++) delete [] allstyles[i]; delete [] allstyles; - // concatenate field strings from all sub-styles + // set field strings from all substyles + + fieldstrings = new FieldStrings[nstyles]; + + for (int k = 0; k < nstyles; k++) { + fieldstrings[k].fstr = new char*[NFIELDSTRINGS]; + fieldstrings[k].fstr[0] = styles[k]->fields_grow; + fieldstrings[k].fstr[1] = styles[k]->fields_copy; + fieldstrings[k].fstr[2] = styles[k]->fields_comm; + fieldstrings[k].fstr[3] = styles[k]->fields_comm_vel; + fieldstrings[k].fstr[4] = styles[k]->fields_reverse; + fieldstrings[k].fstr[5] = styles[k]->fields_border; + fieldstrings[k].fstr[6] = styles[k]->fields_border_vel; + fieldstrings[k].fstr[7] = styles[k]->fields_exchange; + fieldstrings[k].fstr[8] = styles[k]->fields_restart; + fieldstrings[k].fstr[9] = styles[k]->fields_create; + fieldstrings[k].fstr[10] = styles[k]->fields_data_atom; + fieldstrings[k].fstr[11] = styles[k]->fields_data_vel; + } + + // merge field strings from all sub-styles + // save concat_grow to check for duplicates of special-case fields + + char *concat_grow;; + char *null = NULL; + + fields_grow = merge_fields(0,fields_grow,1,concat_grow); + fields_copy = merge_fields(1,fields_copy,0,null); + fields_comm = merge_fields(2,fields_comm,0,null); + fields_comm_vel = merge_fields(3,fields_comm_vel,0,null); + fields_reverse = merge_fields(4,fields_reverse,0,null); + fields_border = merge_fields(5,fields_border,0,null); + fields_border_vel = merge_fields(6,fields_border_vel,0,null); + fields_exchange = merge_fields(7,fields_exchange,0,null); + fields_restart = merge_fields(8,fields_restart,0,null); + fields_create = merge_fields(9,fields_create,0,null); + fields_data_atom = merge_fields(10,fields_data_atom,0,null); + fields_data_vel = merge_fields(11,fields_data_vel,0,null); + + // check concat_grow for multiple special-case fields + // may cause issues with style-specific create_atom() and data_atom() methods + // issue warnings if appear in multiple sub-styles + + const char *dupfield[] = {"radius","rmass"}; + int ndupfield = 2; + char *ptr; + + for (int idup = 0; idup < ndupfield; idup++) { + char *dup = (char *) dupfield[idup]; + ptr = strstr(concat_grow,dup); + if (strstr(ptr+1,dup)) { + char str[128]; + sprintf(str,"Peratom %s is in multiple sub-styles - " + "must be used consistently",dup); + if (comm->me == 0) error->warning(FLERR,str); + } + } - concatenate_fields(); + delete [] concat_grow; - // parent AtomVec will now operate on concatenated fields + // parent AtomVec can now operate on merged fields setup_fields(); } /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::concatenate_fields() +void AtomVecHybrid::init() { - for (int k = 0; k < nstyles; k++) { - concatenate(fields_grow,styles[k]->fields_grow); - concatenate(fields_copy,styles[k]->fields_copy); - concatenate(fields_comm,styles[k]->fields_comm); - concatenate(fields_comm_vel,styles[k]->fields_comm_vel); - concatenate(fields_reverse,styles[k]->fields_reverse); - concatenate(fields_border,styles[k]->fields_border); - concatenate(fields_border_vel,styles[k]->fields_border_vel); - concatenate(fields_exchange,styles[k]->fields_exchange); - concatenate(fields_restart,styles[k]->fields_restart); - concatenate(fields_create,styles[k]->fields_create); - concatenate(fields_data_atom,styles[k]->fields_data_atom); - concatenate(fields_data_vel,styles[k]->fields_data_vel); - } + AtomVec::init(); + for (int k = 0; k < nstyles; k++) styles[k]->init(); } /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::concatenate(char *&root, char *add) +void AtomVecHybrid::force_clear(int n, size_t nbytes) { - /* - char **rootwords,**addwords; - int nroot = parse(root,rootwords); - int nadd = parse(add,addwords); + for (int k = 0; k < nstyles; k++) + if (styles[k]->forceclearflag) styles[k]->force_clear(n,nbytes); +} - for (int iadd = 0; iadd < nadd; iadd++) { - if (check(addwords[iadd],nroot,rootwords)) continue; - addone(addwords[iadd],nroot,rootwords); - } - */ +/* ---------------------------------------------------------------------- + modify values for AtomVec::pack_restart() to pack +------------------------------------------------------------------------- */ + +void AtomVecHybrid::pack_restart_pre(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->pack_restart_pre(ilocal); +} + +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_restart() +------------------------------------------------------------------------- */ + +void AtomVecHybrid::pack_restart_post(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->pack_restart_post(ilocal); +} + +/* ---------------------------------------------------------------------- + initialize other atom quantities after AtomVec::unpack_restart() +------------------------------------------------------------------------- */ + +void AtomVecHybrid::unpack_restart_init(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->unpack_restart_init(ilocal); +} + +/* ---------------------------------------------------------------------- + initialize non-zero atom quantities +------------------------------------------------------------------------- */ + +void AtomVecHybrid::create_atom_post(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->create_atom_post(ilocal); +} + +/* ---------------------------------------------------------------------- + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVecHybrid::data_atom_post(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->data_atom_post(ilocal); +} + +/* ---------------------------------------------------------------------- + modify values for AtomVec::pack_data() to pack +------------------------------------------------------------------------- */ + +void AtomVecHybrid::pack_data_pre(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->pack_data_pre(ilocal); +} + +/* ---------------------------------------------------------------------- + unmodify values packed by AtomVec::pack_data() +------------------------------------------------------------------------- */ + +void AtomVecHybrid::pack_data_post(int ilocal) +{ + for (int k = 0; k < nstyles; k++) + styles[k]->pack_data_post(ilocal); } /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::init() +void AtomVecHybrid::copy_bonus(int i, int j, int delflag) { - AtomVec::init(); - for (int k = 0; k < nstyles; k++) styles[k]->init(); + for (int k = 0; k < nstyles_bonus; k++) + styles_bonus[k]->copy_bonus(i,j,delflag); } +// NOTE: need a clear_bonus() ? + /* ---------------------------------------------------------------------- */ -void AtomVecHybrid::force_clear(int n, size_t nbytes) +int AtomVecHybrid::pack_comm_bonus(int n, int *list, double *buf) { - for (int k = 0; k < nstyles; k++) - if (styles[k]->forceclearflag) styles[k]->force_clear(n,nbytes); + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->pack_comm_bonus(n,list,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +void AtomVecHybrid::unpack_comm_bonus(int n, int first, double *buf) +{ + for (int k = 0; k < nstyles_bonus; k++) + styles_bonus[k]->unpack_comm_bonus(n,first,buf); +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::pack_border_bonus(int n, int *list, double *buf) +{ + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->pack_border_bonus(n,list,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::unpack_border_bonus(int n, int first, double *buf) +{ + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->unpack_border_bonus(n,first,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::pack_exchange_bonus(int i, double *buf) +{ + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->pack_exchange_bonus(i,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::unpack_exchange_bonus(int ilocal, double *buf) +{ + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->unpack_exchange_bonus(ilocal,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::size_restart_bonus() +{ + int n = 0; + for (int k = 0; k < nstyles_bonus; k++) + n += styles_bonus[k]->size_restart_bonus(); + return n; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::pack_restart_bonus(int i, double *buf) +{ + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->pack_restart_bonus(i,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +int AtomVecHybrid::unpack_restart_bonus(int ilocal, double *buf) +{ + int m = 0; + for (int k = 0; k < nstyles_bonus; k++) + m += styles_bonus[k]->unpack_restart_bonus(ilocal,buf); + return m; +} + +/* ---------------------------------------------------------------------- */ + +bigint AtomVecHybrid::memory_usage_bonus() +{ + bigint bytes = 0; + for (int k = 0; k < nstyles_bonus; k++) + bytes += styles_bonus[k]->memory_usage_bonus(); + return bytes; } /* ---------------------------------------------------------------------- @@ -179,6 +450,75 @@ void AtomVecHybrid::pack_property_atom(int multiindex, double *buf, styles[k]->pack_property_atom(index,buf,nvalues,groupbit); } +// ---------------------------------------------------------------------- +// internal methods +// ---------------------------------------------------------------------- + +/* ---------------------------------------------------------------------- + merge fields and remove duplicate fields + concat = root + Inum fields string from all substyles + return dedup = concat with duplicate fields removed + if concat_flag set, also return concat (w/ duplicates) + so caller can check for problematic fields, call will free it +------------------------------------------------------------------------- */ + +char *AtomVecHybrid::merge_fields(int inum, char *root, + int concat_flag, char *&concat_str) +{ + // create concatenated string of length size from root + all substyles + + int size = strlen(root) + 1; + for (int k = 0; k < nstyles; k++) + size += strlen(fieldstrings[k].fstr[inum]) + 1; + + char *concat = new char[size]; + strcpy(concat,root); + + for (int k = 0; k < nstyles; k++) { + if (strlen(concat)) strcat(concat," "); + strcat(concat,fieldstrings[k].fstr[inum]); + } + + // identify unique words in concatenated string + + char *copystr; + char **words; + int nwords = tokenize(concat,words,copystr); + int *unique = new int[nwords]; + + for (int i = 0; i < nwords; i++) { + unique[i] = 1; + for (int j = 0; j < i; j++) + if (strcmp(words[i],words[j]) == 0) unique[i] = 0; + } + + // construct a new deduped string + + char *dedup = new char[size]; + dedup[0] = '\0'; + + for (int i = 0; i < nwords; i++) { + if (!unique[i]) continue; + strcat(dedup,words[i]); + if (i < nwords-1) strcat(dedup," "); + } + + // clean up or return concat + + if (concat_flag) concat_str = concat; + else delete [] concat; + + // clean up + + delete [] copystr; + delete [] words; + delete [] unique; + + // return final concatenated, deduped string + + return dedup; +} + /* ---------------------------------------------------------------------- allstyles = list of all atom styles in this LAMMPS executable ------------------------------------------------------------------------- */ diff --git a/src/atom_vec_hybrid.h b/src/atom_vec_hybrid.h index 41067d44f2..83d29112dd 100644 --- a/src/atom_vec_hybrid.h +++ b/src/atom_vec_hybrid.h @@ -35,6 +35,33 @@ class AtomVecHybrid : public AtomVec { void process_args(int, char **); void init(); void force_clear(int, size_t); + + void copy_bonus(int, int, int); + void clear_bonus() {} + int pack_comm_bonus(int, int *, double *); + void unpack_comm_bonus(int, int, double *); + int pack_border_bonus(int, int *, double *); + int unpack_border_bonus(int, int, double *); + int pack_exchange_bonus(int, double *); + int unpack_exchange_bonus(int, double *); + int size_restart_bonus(); + int pack_restart_bonus(int, double *); + int unpack_restart_bonus(int, double *); + bigint memory_usage_bonus(); + + void pack_restart_pre(int); + void pack_restart_post(int); + void unpack_restart_init(int); + void create_atom_post(int); + void data_atom_post(int); + void pack_data_pre(int); + void pack_data_post(int); + + //void create_atom_post(int); + //void data_atom_post(int); + //void pack_data_pre(int); + //void pack_data_post(int); + int property_atom(char *); void pack_property_atom(int, double *, int, int); @@ -42,8 +69,15 @@ class AtomVecHybrid : public AtomVec { int nallstyles; char **allstyles; - void concatenate_fields(); - void concatenate(char *&, char *); + struct FieldStrings { + char **fstr; + }; + FieldStrings *fieldstrings; + + int nstyles_bonus; + class AtomVec **styles_bonus; + + char *merge_fields(int, char *, int, char *&); void build_styles(); int known_style(char *); }; diff --git a/src/atom_vec_line.cpp b/src/atom_vec_line.cpp index 3b806c959e..ded2f88c2f 100644 --- a/src/atom_vec_line.cpp +++ b/src/atom_vec_line.cpp @@ -50,12 +50,12 @@ AtomVecLine::AtomVecLine(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "molecule radius rmass omega torque line"; fields_copy = (char *) "molecule radius rmass omega"; - fields_comm = NULL; + fields_comm = (char *) ""; fields_comm_vel = (char *) "omega"; fields_reverse = (char *) "torque"; fields_border = (char *) "molecule radius rmass"; @@ -64,7 +64,7 @@ AtomVecLine::AtomVecLine(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "molecule radius rmass omega"; fields_create = (char *) "molecule radius rmass omega line"; fields_data_atom = (char *) "id molecule type line rmass x"; - fields_data_vel = (char *) "omega"; + fields_data_vel = (char *) "id v omega"; setup_fields(); } diff --git a/src/atom_vec_line.h b/src/atom_vec_line.h index a8bc8fd1bc..a47843f4f2 100644 --- a/src/atom_vec_line.h +++ b/src/atom_vec_line.h @@ -40,7 +40,6 @@ class AtomVecLine : public AtomVec { void clear_bonus(); int pack_comm_bonus(int, int *, double *); void unpack_comm_bonus(int, int, double *); - int pack_reverse_bonus(int, int, double *); int pack_border_bonus(int, int *, double *); int unpack_border_bonus(int, int, double *); int pack_exchange_bonus(int, double *); diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index 5ae4c0ca21..6796f9c8f2 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -36,12 +36,12 @@ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "radius rmass omega torque"; fields_copy = (char *) "radius rmass omega"; - fields_comm = NULL; + fields_comm = (char *) ""; fields_comm_vel = (char *) "omega"; fields_reverse = (char *) "torque"; fields_border = (char *) "radius rmass"; @@ -50,7 +50,7 @@ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "radius rmass omega"; fields_create = (char *) "radius rmass omega"; fields_data_atom = (char *) "id type radius rmass x"; - fields_data_vel = (char *) "omega"; + fields_data_vel = (char *) "id v omega"; setup_fields(); } diff --git a/src/atom_vec_tri.cpp b/src/atom_vec_tri.cpp index 6da0ef7015..32d75c16f3 100644 --- a/src/atom_vec_tri.cpp +++ b/src/atom_vec_tri.cpp @@ -52,12 +52,12 @@ AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp) // strings with peratom variables to include in each AtomVec method // strings cannot contain fields in corresponding AtomVec default strings - // order of fields in the string does not matter - // except fields_data_atom and fields_data_vel which must match data file + // order of fields in a string does not matter + // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) "molecule radius rmass omega angmom torque tri"; fields_copy = (char *) "molecule radius rmass omega angmom"; - fields_comm = NULL; + fields_comm = (char *) ""; fields_comm_vel = (char *) "omega angmom"; fields_reverse = (char *) "torque"; fields_border = (char *) "molecule radius rmass"; @@ -66,7 +66,7 @@ AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "molecule radius rmass omega angmom"; fields_create = (char *) "molecule radius rmass omega angmom line"; fields_data_atom = (char *) "id molecule type tri rmass x"; - fields_data_vel = (char *) "omega angmom"; + fields_data_vel = (char *) "id v omega angmom"; setup_fields(); } diff --git a/src/atom_vec_tri.h b/src/atom_vec_tri.h index 3c701067b2..ad4c0103ca 100644 --- a/src/atom_vec_tri.h +++ b/src/atom_vec_tri.h @@ -42,7 +42,6 @@ class AtomVecTri : public AtomVec { void clear_bonus(); int pack_comm_bonus(int, int *, double *); void unpack_comm_bonus(int, int, double *); - int pack_reverse_bonus(int, int, double *); int pack_border_bonus(int, int *, double *); int unpack_border_bonus(int, int, double *); int pack_exchange_bonus(int, double *); -- GitLab From 9e52980aaae343c0c2dc912ff5b44ee7a46b8eb5 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 3 Dec 2019 11:15:16 -0700 Subject: [PATCH 010/577] all of remaining USER package styles except AWPMD --- src/SPIN/atom_vec_spin.cpp | 12 +- src/USER-EFF/atom_vec_electron.cpp | 17 +- src/USER-MESO/atom_vec_edpd.cpp | 20 +- src/USER-MESO/atom_vec_edpd.h | 1 + src/USER-MESO/atom_vec_mdpd.cpp | 895 +------------------ src/USER-MESO/atom_vec_mdpd.h | 43 +- src/USER-MESO/atom_vec_tdpd.cpp | 846 +----------------- src/USER-MESO/atom_vec_tdpd.h | 32 +- src/USER-SMD/atom_vec_smd.cpp | 1338 +++------------------------- src/USER-SMD/atom_vec_smd.h | 59 +- src/USER-SPH/atom_vec_meso.cpp | 971 +------------------- src/USER-SPH/atom_vec_meso.h | 43 +- src/atom.cpp | 128 ++- src/atom.h | 16 +- src/atom_vec_hybrid.h | 5 - src/atom_vec_sphere.cpp | 7 +- 16 files changed, 362 insertions(+), 4071 deletions(-) diff --git a/src/SPIN/atom_vec_spin.cpp b/src/SPIN/atom_vec_spin.cpp index a8ff15492a..638a3b8021 100644 --- a/src/SPIN/atom_vec_spin.cpp +++ b/src/SPIN/atom_vec_spin.cpp @@ -62,14 +62,16 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) } /* ---------------------------------------------------------------------- - clear all forces (mechanical and magnetic) + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector + include f b/c this is invoked from within SPIN pair styles ------------------------------------------------------------------------- */ -void AtomVecSpin::force_clear(int /*n*/, size_t nbytes) +void AtomVecSpin::force_clear(int n, size_t nbytes) { - memset(&atom->f[0][0],0,3*nbytes); - memset(&atom->fm[0][0],0,3*nbytes); - memset(&atom->fm_long[0][0],0,3*nbytes); + memset(&atom->f[n][0],0,3*nbytes); + memset(&atom->fm[n][0],0,3*nbytes); + memset(&atom->fm_long[n][0],0,3*nbytes); } /* ---------------------------------------------------------------------- diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp index 0bad0f115f..3688f7f582 100644 --- a/src/USER-EFF/atom_vec_electron.cpp +++ b/src/USER-EFF/atom_vec_electron.cpp @@ -18,14 +18,8 @@ #include "atom_vec_electron.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" #include "citeme.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -46,6 +40,8 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) { if (lmp->citeme) lmp->citeme->add(cite_user_eff_package); + mass_type = 1; + molecular = 0; forceclearflag = 1; atom->ecp_flag = 0; @@ -75,11 +71,14 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) setup_fields(); } -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector +------------------------------------------------------------------------- */ -void AtomVecElectron::force_clear(int /*n*/, size_t nbytes) +void AtomVecElectron::force_clear(int n, size_t nbytes) { - memset(&atom->erforce[0],0,nbytes); + memset(&atom->erforce[n],0,nbytes); } /* ---------------------------------------------------------------------- diff --git a/src/USER-MESO/atom_vec_edpd.cpp b/src/USER-MESO/atom_vec_edpd.cpp index b4602c760c..7a031c256b 100644 --- a/src/USER-MESO/atom_vec_edpd.cpp +++ b/src/USER-MESO/atom_vec_edpd.cpp @@ -29,9 +29,6 @@ using namespace LAMMPS_NS; AtomVecEDPD::AtomVecEDPD(LAMMPS *lmp) : AtomVec(lmp) { - if (strcmp(update->unit_style,"lj") != 0) - error->all(FLERR,"Atom style edpd requires lj units"); - molecular = 0; mass_type = 1; forceclearflag = 1; @@ -62,9 +59,22 @@ AtomVecEDPD::AtomVecEDPD(LAMMPS *lmp) : AtomVec(lmp) /* ---------------------------------------------------------------------- */ -void AtomVecEDPD::force_clear(int /*n*/, size_t nbytes) +void AtomVecEDPD::init() +{ + AtomVec::init(); + + if (strcmp(update->unit_style,"lj") != 0) + error->all(FLERR,"Atom style edpd requires lj units"); +} + +/* ---------------------------------------------------------------------- + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector +------------------------------------------------------------------------- */ + +void AtomVecEDPD::force_clear(int n, size_t nbytes) { - memset(&atom->edpd_flux[0],0,nbytes); + memset(&atom->edpd_flux[n],0,nbytes); } /* ---------------------------------------------------------------------- diff --git a/src/USER-MESO/atom_vec_edpd.h b/src/USER-MESO/atom_vec_edpd.h index 7d41b51665..bb667ae792 100644 --- a/src/USER-MESO/atom_vec_edpd.h +++ b/src/USER-MESO/atom_vec_edpd.h @@ -27,6 +27,7 @@ namespace LAMMPS_NS { class AtomVecEDPD : public AtomVec { public: AtomVecEDPD(class LAMMPS *); + void init(); void force_clear(int, size_t); void create_atom_post(int); void data_atom_post(int); diff --git a/src/USER-MESO/atom_vec_mdpd.cpp b/src/USER-MESO/atom_vec_mdpd.cpp index 4c9db36645..eefda1ff6a 100644 --- a/src/USER-MESO/atom_vec_mdpd.cpp +++ b/src/USER-MESO/atom_vec_mdpd.cpp @@ -14,14 +14,8 @@ #include "atom_vec_mdpd.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" #include "update.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -29,865 +23,63 @@ using namespace LAMMPS_NS; AtomVecMDPD::AtomVecMDPD(LAMMPS *lmp) : AtomVec(lmp) { - if(strcmp(update->unit_style,"lj") != 0) - error->all(FLERR,"Atom style mdpd requires lj units"); - molecular = 0; mass_type = 1; forceclearflag = 1; - comm_x_only = comm_f_only = 0; - comm->ghost_velocity = 1; - - size_forward = 3 + 4; // 3 + rho + vest[3], that means we may only communicate 4 in hybrid - size_reverse = 3 + 1; // 3 + drho - size_border = 6 + 4; // 6 + rho + vest[3] - size_velocity = 3; - size_data_atom = 6; - size_data_vel = 4; - xcol_data = 4; - atom->rho_flag = 1; atom->vest_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n - ------------------------------------------------------------------------- */ - -void AtomVecMDPD::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag, nmax, "atom:tag"); - type = memory->grow(atom->type, nmax, "atom:type"); - mask = memory->grow(atom->mask, nmax, "atom:mask"); - image = memory->grow(atom->image, nmax, "atom:image"); - x = memory->grow(atom->x, nmax, 3, "atom:x"); - v = memory->grow(atom->v, nmax, 3, "atom:v"); - f = memory->grow(atom->f, nmax*comm->nthreads, 3, "atom:f"); - - rho = memory->grow(atom->rho, nmax, "atom:rho"); - drho = memory->grow(atom->drho, nmax*comm->nthreads, "atom:drho"); - vest = memory->grow(atom->vest, nmax, 3, "atom:vest"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs - ------------------------------------------------------------------------- */ - -void AtomVecMDPD::grow_reset() { - tag = atom->tag; - type = atom->type; - mask = atom->mask; - image = atom->image; - x = atom->x; - v = atom->v; - f = atom->f; - rho = atom->rho; - drho = atom->drho; - vest = atom->vest; -} -/* ---------------------------------------------------------------------- */ + // 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 -void AtomVecMDPD::copy(int i, int j, int delflag) { - //printf("in AtomVecMDPD::copy\n"); - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; + fields_grow = (char *) "rho drho vest"; + fields_copy = (char *) "rho drho vest"; + fields_comm = (char *) "rho vest"; + fields_comm_vel = (char *) "rho vest"; + fields_reverse = (char *) "drho"; + fields_border = (char *) "rho vest"; + fields_border_vel = (char *) "rho vest"; + fields_exchange = (char *) "rho vest"; + fields_restart = (char * ) "rho vest"; + fields_create = (char *) "rho drho vest"; + fields_data_atom = (char *) "id type rho x"; + fields_data_vel = (char *) "id v"; - rho[j] = rho[i]; - drho[j] = drho[i]; - vest[j][0] = vest[i][0]; - vest[j][1] = vest[i][1]; - vest[j][2] = vest[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i, j,delflag); + setup_fields(); } /* ---------------------------------------------------------------------- */ -void AtomVecMDPD::force_clear(int n, size_t nbytes) +void AtomVecMDPD::init() { - memset(&drho[n],0,nbytes); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_comm_hybrid(int n, int *list, double *buf) { - //printf("in AtomVecMDPD::pack_comm_hybrid\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::unpack_comm_hybrid(int n, int first, double *buf) { - //printf("in AtomVecMDPD::unpack_comm_hybrid\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - rho[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_border_hybrid(int n, int *list, double *buf) { - //printf("in AtomVecMDPD::pack_border_hybrid\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::unpack_border_hybrid(int n, int first, double *buf) { - //printf("in AtomVecMDPD::unpack_border_hybrid\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - rho[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_reverse_hybrid(int n, int first, double *buf) { - //printf("in AtomVecMDPD::pack_reverse_hybrid\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = drho[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::unpack_reverse_hybrid(int n, int *list, double *buf) { - //printf("in AtomVecMDPD::unpack_reverse_hybrid\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - drho[j] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_comm(int n, int *list, double *buf, int pbc_flag, - int *pbc) { - //printf("in AtomVecMDPD::pack_comm\n"); - int i, j, m; - double dx, dy, dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0] * domain->xprd + pbc[5] * domain->xy + pbc[4] * domain->xz; - dy = pbc[1] * domain->yprd + pbc[3] * domain->yz; - dz = pbc[2] * domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, - int *pbc) { - //printf("in AtomVecMDPD::pack_comm_vel\n"); - int i, j, m; - double dx, dy, dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0] * domain->xprd + pbc[5] * domain->xy + pbc[4] * domain->xz; - dy = pbc[1] * domain->yprd + pbc[3] * domain->yz; - dz = pbc[2] * domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMDPD::unpack_comm(int n, int first, double *buf) { - //printf("in AtomVecMDPD::unpack_comm\n"); - int i, m, last; - - 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++]; - rho[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMDPD::unpack_comm_vel(int n, int first, double *buf) { - //printf("in AtomVecMDPD::unpack_comm_vel\n"); - int i, m, last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - rho[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_reverse(int n, int first, double *buf) { - //printf("in AtomVecMDPD::pack_reverse\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = drho[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMDPD::unpack_reverse(int n, int *list, double *buf) { - //printf("in AtomVecMDPD::unpack_reverse\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - drho[j] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_border(int n, int *list, double *buf, int pbc_flag, - int *pbc) { - //printf("in AtomVecMDPD::pack_border\n"); - int i, j, m; - double dx, dy, dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_border_vel(int n, int *list, double *buf, int pbc_flag, - int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - dvx = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; - dvy = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; - dvz = pbc[2] * h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - buf[m++] = rho[j]; - buf[m++] = vest[j][0] + dvx; - buf[m++] = vest[j][1] + dvy; - buf[m++] = vest[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMDPD::unpack_border(int n, int first, double *buf) { - //printf("in AtomVecMDPD::unpack_border\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) - grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - rho[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMDPD::unpack_border_vel(int n, int first, double *buf) { - //printf("in AtomVecMDPD::unpack_border_vel\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) - grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - rho[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them - ------------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_exchange(int i, double *buf) { - //printf("in AtomVecMDPD::pack_exchange\n"); - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = rho[i]; - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i, &buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMDPD::unpack_exchange(double *buf) { - //printf("in AtomVecMDPD::unpack_exchange\n"); - int nlocal = atom->nlocal; - if (nlocal == nmax) - grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - rho[nlocal] = buf[m++]; - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal, - &buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes - ------------------------------------------------------------------------- */ - -int AtomVecMDPD::size_restart() { - int i; - - int nlocal = atom->nlocal; - int n = 15 * nlocal; // 11 + rho + vest[3] - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive - ------------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_restart(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = rho[i]; - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i, &buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - ------------------------------------------------------------------------- */ - -int AtomVecMDPD::unpack_restart(double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra, nmax, atom->nextra_store, "atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - rho[nlocal] = buf[m++]; - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) - extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults - ------------------------------------------------------------------------- */ - -void AtomVecMDPD::create_atom(int itype, double *coord) { - int nlocal = atom->nlocal; - if (nlocal == nmax) - grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - rho[nlocal] = 0.0; - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - drho[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities - ------------------------------------------------------------------------- */ - -void AtomVecMDPD::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - - rho[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - drho[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style - ------------------------------------------------------------------------- */ - -int AtomVecMDPD::data_atom_hybrid(int nlocal, char **values) -{ - rho[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - return 3; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecMDPD::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = rho[i]; - buf[i][3] = x[i][0]; - buf[i][4] = x[i][1]; - buf[i][5] = x[i][2]; - buf[i][6] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][8] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecMDPD::pack_data_hybrid(int i, double *buf) -{ - buf[0] = rho[i]; - return 3; + if (strcmp(update->unit_style,"lj") != 0) + error->all(FLERR,"Atom style mdpd requires lj units"); } /* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector ------------------------------------------------------------------------- */ -void AtomVecMDPD::write_data(FILE *fp, int n, double **buf) +void AtomVecMDPD::force_clear(int n, size_t nbytes) { - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %-1.16e " - "%d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4],buf[i][5], - (int) ubuf(buf[i][6]).i,(int) ubuf(buf[i][7]).i, - (int) ubuf(buf[i][8]).i); + memset(&atom->drho[n],0,nbytes); } /* ---------------------------------------------------------------------- - write hybrid atom info to data file + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -int AtomVecMDPD::write_data_hybrid(FILE *fp, double *buf) +void AtomVecMDPD::data_atom_post(int ilocal) { - fprintf(fp," %-1.16e",buf[0]); - return 3; + atom->drho[ilocal] = 0.0; + atom->vest[ilocal][0] = 0.0; + atom->vest[ilocal][1] = 0.0; + atom->vest[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- @@ -912,15 +104,17 @@ void AtomVecMDPD::pack_property_atom(int index, double *buf, { int *mask = atom->mask; int nlocal = atom->nlocal; - int n = 0; + int n = 0; if (index == 0) { + double *rho = atom->rho; 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 == 1) { + double *drho = atom->drho; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = drho[i]; else buf[n] = 0.0; @@ -928,24 +122,3 @@ void AtomVecMDPD::pack_property_atom(int index, double *buf, } } } - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory - ------------------------------------------------------------------------- */ - -bigint AtomVecMDPD::memory_usage() { - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag, nmax); - if (atom->memcheck("type")) bytes += memory->usage(type, nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask, nmax); - if (atom->memcheck("image")) bytes += memory->usage(image, nmax); - if (atom->memcheck("x")) bytes += memory->usage(x, nmax, 3); - if (atom->memcheck("v")) bytes += memory->usage(v, nmax, 3); - if (atom->memcheck("f")) bytes += memory->usage(f, nmax*comm->nthreads, 3); - if (atom->memcheck("rho")) bytes += memory->usage(rho, nmax); - if (atom->memcheck("drho")) bytes += memory->usage(drho, nmax*comm->nthreads); - if (atom->memcheck("vest")) bytes += memory->usage(vest, nmax, 3); - - return bytes; -} diff --git a/src/USER-MESO/atom_vec_mdpd.h b/src/USER-MESO/atom_vec_mdpd.h index 9e9ffcdcf2..0eb4fff2df 100644 --- a/src/USER-MESO/atom_vec_mdpd.h +++ b/src/USER-MESO/atom_vec_mdpd.h @@ -27,50 +27,11 @@ namespace LAMMPS_NS { class AtomVecMDPD : public AtomVec { public: AtomVecMDPD(class LAMMPS *); - ~AtomVecMDPD() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); + void init(); void force_clear(int, size_t); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_comm_hybrid(int, int *, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_border_hybrid(int, int *, double *); - int unpack_border_hybrid(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); + void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); - bigint memory_usage(); - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *rho, *drho; - double **vest; // estimated velocity during force computation }; } diff --git a/src/USER-MESO/atom_vec_tdpd.cpp b/src/USER-MESO/atom_vec_tdpd.cpp index 74ac47066b..55284f69a2 100644 --- a/src/USER-MESO/atom_vec_tdpd.cpp +++ b/src/USER-MESO/atom_vec_tdpd.cpp @@ -14,12 +14,7 @@ #include "atom_vec_tdpd.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" #include "update.h" -#include "memory.h" #include "error.h" #include "utils.h" @@ -29,29 +24,30 @@ using namespace LAMMPS_NS; AtomVecTDPD::AtomVecTDPD(LAMMPS *lmp) : AtomVec(lmp) { - if(strcmp(update->unit_style,"lj") != 0) - error->all(FLERR,"Atom style edpd requires lj units"); - molecular = 0; mass_type = 1; forceclearflag = 1; - comm_x_only = comm_f_only = 0; - comm->ghost_velocity = 1; - - cc_species = 0; // for now, reset in process_args() - - size_forward = 3 + cc_species + 3; //vest[3] - size_reverse = 3 + cc_species; - size_border = 6 + cc_species + 3; //vest[3] - size_velocity = 3; - // for data_atom, we read id + type + xyz[3] + cc[i] where i=1,cc_species - size_data_atom = 5 + cc_species; - size_data_vel = 4; - xcol_data = 3; - atom->tdpd_flag = 1; atom->vest_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 = (char *) "cc cc_flux vest"; + fields_copy = (char *) "cc vest"; + fields_comm = (char *) "cc vest"; + fields_comm_vel = (char *) "cc vest"; + fields_reverse = (char *) "cc_flux"; + fields_border = (char *) "cc vest"; + fields_border_vel = (char *) "cc vest"; + fields_exchange = (char *) "cc vest"; + fields_restart = (char * ) "cc vest"; + fields_create = (char *) "cc vest"; + fields_data_atom = (char *) "id type x cc"; + fields_data_vel = (char *) "id v"; } /* ---------------------------------------------------------------------- @@ -66,812 +62,42 @@ void AtomVecTDPD::process_args(int narg, char **arg) atom->cc_species = utils::inumeric(FLERR,arg[0],false,lmp); cc_species = atom->cc_species; - // reset sizes that depend on cc_species - - size_forward = 3 + cc_species + 3; - size_reverse = 3 + cc_species; - size_border = 6 + cc_species + 3; - size_data_atom = 5 + cc_species; -} - -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecTDPD::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - cc = memory->grow(atom->cc,nmax*comm->nthreads,cc_species,"atom:cc"); - cc_flux = memory->grow(atom->cc_flux,nmax*comm->nthreads,cc_species, - "atom:cc_flux"); - vest = memory->grow(atom->vest, nmax, 3, "atom:vest"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); -} - -/* ---------------------------------------------------------------------- - reset local array ptrs -------------------------------------------------------------------------- */ - -void AtomVecTDPD::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - cc = atom->cc; cc_flux = atom->cc_flux; - vest = atom->vest; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecTDPD::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - for(int k = 0; k < cc_species; k++) - cc[j][k] = cc[i][k]; - - vest[j][0] = vest[i][0]; - vest[j][1] = vest[i][1]; - vest[j][2] = vest[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - - -void AtomVecTDPD::force_clear(int n, size_t nbytes) -{ - memset(&cc_flux[n][0],0,cc_species*nbytes); -} - - -/* ---------------------------------------------------------------------- */ - -int AtomVecTDPD::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,k,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - - for(k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - - for(k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTDPD::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,k,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - - for(k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - - for(k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - for(k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTDPD::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - - for(int k = 0; k < cc_species; k++) - cc[i][k] = buf[m++]; - - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTDPD::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - for(int k = 0; k < cc_species; k++) - cc[i][k] = buf[m++]; - - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTDPD::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc_flux[i][k]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTDPD::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - for(int k = 0; k < cc_species; k++) - cc_flux[j][k] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTDPD::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecTDPD::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[j][k]; - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTDPD::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - for(int k = 0; k < cc_species; k++) - cc[i][k] = buf[m++]; - - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecTDPD::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - for(int k = 0; k < cc_species; k++) - cc[i][k] = buf[m++]; - - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } + atom->add_peratom_change_columns("cc",cc_species); + atom->add_peratom_change_columns("cc_species",cc_species); - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecTDPD::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[i][k]; + // delay setting up of fields until now - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; + setup_fields(); } /* ---------------------------------------------------------------------- */ -int AtomVecTDPD::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - for(int k = 0; k < cc_species; k++) - cc[nlocal][k] = buf[m++]; - - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecTDPD::size_restart() +void AtomVecTDPD::init() { - int i; + AtomVec::init(); - int nlocal = atom->nlocal; - int n = (11 + cc_species + 3) * nlocal; // 11 + cc[i] + vest[3] - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; + if (strcmp(update->unit_style,"lj") != 0) + error->all(FLERR,"Atom style tdpd requires lj units"); } /* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector ------------------------------------------------------------------------- */ -int AtomVecTDPD::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - for(int k = 0; k < cc_species; k++) - buf[m++] = cc[i][k]; - - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecTDPD::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - for(int k = 0; k < cc_species; k++) - cc[nlocal][k] = buf[m++]; - - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults -------------------------------------------------------------------------- */ - -void AtomVecTDPD::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - for(int k = 0; k < cc_species; k++) - cc[nlocal][k] = 0.0; - - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities -------------------------------------------------------------------------- */ - -void AtomVecTDPD::data_atom(double *coord, imageint imagetmp, char **values) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - for(int k = 0; k < cc_species; k++) - cc[nlocal][k] = utils::numeric(FLERR,values[5+k],true,lmp); - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecTDPD::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = x[i][0]; - buf[i][3] = x[i][1]; - buf[i][4] = x[i][2]; - buf[i][5] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][6] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][7] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - for(int k = 0; k < cc_species; k++) - buf[i][8+k] = cc[i][k]; - } -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecTDPD::write_data(FILE *fp, int n, double **buf) +void AtomVecTDPD::force_clear(int n, size_t nbytes) { - for (int i = 0; i < n; i++){ - fprintf(fp,TAGINT_FORMAT " %d %-1.16e %-1.16e %-1.16e %d %d %d", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4], - (int) ubuf(buf[i][5]).i,(int) ubuf(buf[i][6]).i, - (int) ubuf(buf[i][7]).i); - for(int k = 0; k < cc_species; k++) - fprintf(fp," %-1.16e",buf[i][8+k]); - fprintf(fp,"\n"); - } + memset(&atom->cc_flux[n][0],0,cc_species*nbytes); } /* ---------------------------------------------------------------------- - return # of bytes of allocated memory + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -bigint AtomVecTDPD::memory_usage() +void AtomVecTDPD::data_atom_post(int ilocal) { - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - if (atom->memcheck("cc")) bytes += memory->usage(cc,nmax*comm->nthreads,cc_species); - if (atom->memcheck("cc_flux")) bytes += memory->usage(cc_flux,nmax*comm->nthreads,cc_species); - if (atom->memcheck("vest")) bytes += memory->usage(vest, nmax); - - return bytes; + atom->vest[ilocal][0] = 0.0; + atom->vest[ilocal][1] = 0.0; + atom->vest[ilocal][2] = 0.0; } diff --git a/src/USER-MESO/atom_vec_tdpd.h b/src/USER-MESO/atom_vec_tdpd.h index 86e9ae4bb8..7321859fb4 100644 --- a/src/USER-MESO/atom_vec_tdpd.h +++ b/src/USER-MESO/atom_vec_tdpd.h @@ -27,40 +27,12 @@ namespace LAMMPS_NS { class AtomVecTDPD : public AtomVec { public: AtomVecTDPD(class LAMMPS *); - virtual ~AtomVecTDPD() {} void process_args(int, char **); - void grow(int); - void grow_reset(); - void copy(int, int, int); + void init(); void force_clear(int, size_t); - virtual int pack_comm(int, int *, double *, int, int *); - virtual int pack_comm_vel(int, int *, double *, int, int *); - virtual void unpack_comm(int, int, double *); - virtual void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - virtual int pack_border(int, int *, double *, int, int *); - virtual int pack_border_vel(int, int *, double *, int, int *); - virtual void unpack_border(int, int, double *); - virtual void unpack_border_vel(int, int, double *); - virtual int pack_exchange(int, double *); - virtual int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - void pack_data(double **); - void write_data(FILE *, int, double **); - bigint memory_usage(); + void data_atom_post(int); protected: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double **vest; // store intermediate velocity for using mvv integrator - double **cc,**cc_flux; int cc_species; }; diff --git a/src/USER-SMD/atom_vec_smd.cpp b/src/USER-SMD/atom_vec_smd.cpp index 604504c5a7..0fada3dc2a 100644 --- a/src/USER-SMD/atom_vec_smd.cpp +++ b/src/USER-SMD/atom_vec_smd.cpp @@ -25,13 +25,7 @@ #include "atom_vec_smd.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -40,1247 +34,139 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : - AtomVec(lmp) { - molecular = 0; +AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) +{ + molecular = 0; + mass_type = 1; + forceclearflag = 1; + + atom->smd_flag = 1; + + atom->radius_flag = 1; + atom->rmass_flag = 1; + atom->vfrac_flag = 1; + atom->contact_radius_flag = 1; + atom->molecule_flag = 1; + atom->smd_data_9_flag = 1; + atom->e_flag = 1; + atom->vest_flag = 1; + atom->smd_stress_flag = 1; + atom->eff_plastic_strain_flag = 1; + atom->x0_flag = 1; + atom->damage_flag = 1; + atom->eff_plastic_strain_rate_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 = (char *) + "de vfrac rmass x0 radius contact_radius molecule " + "smd_data_9 e vest tlsph_stress " + "eff_plastic_strain eff_plastic_strain_rate damage"; + fields_copy = (char *) + "vfrac rmass x0 radius contact_radius molecule e " + "eff_plastic_strain eff_plastic_strain_rate vest " + "smd_data_9 smd_stress damage"; + fields_comm = (char *) "radius vfrac vest e"; + fields_comm_vel = (char *) "radius vfrac vest e"; + fields_reverse = (char *) "de"; + fields_border = (char *) + "x0 molecule radius rmass vfrac contact_radius e " + "eff_plastic_strain smd_data_9 smd_stress"; + fields_border_vel = (char *) + "x0 molecule radius rmass vfrac contact_radius e " + "eff_plastic_strain smd_data_9 smd_stress vest"; + fields_exchange = (char *) + "x0 molecule radius rmass vfrac contact_radius e " + "eff_plastic_strain eff_plastic_strain_rate smd_data_9 smd_stress " + "vest damage"; + fields_restart = (char *) + "x0 molecule radius rmass vfrac contact_radius e " + "eff_plastic_strain eff_plastic_strain_rate smd_data_9 smd_stress " + "vest damage"; + fields_create = (char *) + "x0 vest vfrac rmass radius contact_radius molecule e " + "eff_plastic_strain eff_plastic_strain_rate smd_data_9 smd_stress damage"; + fields_data_atom = (char *) + "id type molecule vfrac rmass radius contact_radius x"; + fields_data_vel = (char *) "id v vest"; - comm_x_only = 0; - comm_f_only = 0; - size_forward = 6; // variables that are changed by time integration - size_reverse = 4; // f[3] + de - size_border = 31; - size_velocity = 6; // v + vest - size_data_atom = 13; // 7 + 3 x0 + 3 x - size_data_vel = 4; - xcol_data = 11; + // set these array sizes based on defines - atom->radius_flag = 1; - atom->rmass_flag = 1; - atom->vfrac_flag = 1; - atom->contact_radius_flag = 1; - atom->molecule_flag = 1; - atom->smd_data_9_flag = 1; - atom->e_flag = 1; - atom->vest_flag = 1; - atom->smd_stress_flag = 1; - atom->eff_plastic_strain_flag = 1; - atom->x0_flag = 1; - atom->damage_flag = 1; - atom->eff_plastic_strain_rate_flag = 1; + atom->add_peratom_change_columns("smd_data_9",NMAT_FULL); + atom->add_peratom_change_columns("smd_stress",NMAT_SYMM); - forceclearflag = 1; - - atom->smd_flag = 1; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSMD::init() { - AtomVec::init(); - - // do nothing here + setup_fields(); } /* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n - ------------------------------------------------------------------------- */ - -void AtomVecSMD::grow(int n) { - if (n == 0) - grow_nmax(); - else - nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR, "Per-processor system is too big"); - - //printf("in grow, nmax is now %d\n", nmax); - - tag = memory->grow(atom->tag, nmax, "atom:tag"); - type = memory->grow(atom->type, nmax, "atom:type"); - mask = memory->grow(atom->mask, nmax, "atom:mask"); - image = memory->grow(atom->image, nmax, "atom:image"); - x = memory->grow(atom->x, nmax, 3, "atom:x"); - v = memory->grow(atom->v, nmax, 3, "atom:v"); + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector + NOTE: does f need to be re-cleared? +------------------------------------------------------------------------- */ - f = memory->grow(atom->f, nmax * comm->nthreads, 3, "atom:f"); - de = memory->grow(atom->de, nmax * comm->nthreads, "atom:de"); - - vfrac = memory->grow(atom->vfrac, nmax, "atom:vfrac"); - rmass = memory->grow(atom->rmass, nmax, "atom:rmass"); - x0 = memory->grow(atom->x0, nmax, 3, "atom:x0"); - radius = memory->grow(atom->radius, nmax, "atom:radius"); - contact_radius = memory->grow(atom->contact_radius, nmax, "atom:contact_radius"); - molecule = memory->grow(atom->molecule, nmax, "atom:molecule"); - smd_data_9 = memory->grow(atom->smd_data_9, nmax, NMAT_FULL, "atom:defgrad_old"); - e = memory->grow(atom->e, nmax, "atom:e"); - vest = memory->grow(atom->vest, nmax, 3, "atom:vest"); - tlsph_stress = memory->grow(atom->smd_stress, nmax, NMAT_SYMM, "atom:tlsph_stress"); - eff_plastic_strain = memory->grow(atom->eff_plastic_strain, nmax, "atom:eff_plastic_strain"); - eff_plastic_strain_rate = memory->grow(atom->eff_plastic_strain_rate, nmax, "atom:eff_plastic_strain_rate"); - damage = memory->grow(atom->damage, nmax, "atom:damage"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); +void AtomVecSMD::force_clear(int n, size_t nbytes) +{ + memset(&atom->de[n],0,nbytes); + memset(&atom->f[n][0],0,3*nbytes); } /* ---------------------------------------------------------------------- - reset local array ptrs - ------------------------------------------------------------------------- */ - -void AtomVecSMD::grow_reset() { - tag = atom->tag; - type = atom->type; - mask = atom->mask; - image = atom->image; - x = atom->x; - v = atom->v; - f = atom->f; - radius = atom->radius; - rmass = atom->rmass; - - vfrac = atom->vfrac; - x0 = atom->x0; - contact_radius = atom->contact_radius; - molecule = atom->molecule; - smd_data_9 = atom->smd_data_9; - e = atom->e; - de = atom->de; - tlsph_stress = atom->smd_stress; - eff_plastic_strain = atom->eff_plastic_strain; - eff_plastic_strain_rate = atom->eff_plastic_strain_rate; - damage = atom->damage; - vest = atom->vest; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J - ------------------------------------------------------------------------- */ - -void AtomVecSMD::copy(int i, int j, int delflag) { - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - vfrac[j] = vfrac[i]; - rmass[j] = rmass[i]; - x0[j][0] = x0[i][0]; - x0[j][1] = x0[i][1]; - x0[j][2] = x0[i][2]; - radius[j] = radius[i]; - contact_radius[j] = contact_radius[i]; - molecule[j] = molecule[i]; - e[j] = e[i]; - eff_plastic_strain[j] = eff_plastic_strain[i]; - eff_plastic_strain_rate[j] = eff_plastic_strain_rate[i]; - vest[j][0] = vest[i][0]; - vest[j][1] = vest[i][1]; - vest[j][2] = vest[i][2]; - - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[j][k] = smd_data_9[i][k]; - } - - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[j][k] = tlsph_stress[i][k]; - } - - damage[j] = damage[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i, j, delflag); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_comm(int /*n*/, int * /*list*/, double * /*buf*/, int /*pbc_flag*/, int * /*pbc*/) { - error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); - return -1; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { - // communicate quantities to ghosts, which are changed by time-integration AND are required on ghost atoms. - - //no need to pack stress or defgrad information here, as these quantities are not required for ghost atoms. - // Inside pair_style tlsph, these quantities are computed and communicated to ghosts. - - // no need to communicate x0 here, as it is not changed by time integration - // if x0 is changed when the ref config is updated, this communication is performed in the fix_integrate/tlsph - // similarily, rmass could be removed here. - // radius should be communicated here for future time-integration of the radius with ulsph (not implemented yet) - int i, j, m; - double dx, dy, dz, dvx, dvy, dvz; - - m = 0; - if (pbc_flag == 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]; //3 - buf[m++] = radius[j]; - buf[m++] = vfrac[j]; // 5 - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; // 8 - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; // 11 - buf[m++] = e[j]; // 12 - - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0] * domain->xprd + pbc[5] * domain->xy + pbc[4] * domain->xz; - dy = pbc[1] * domain->yprd + pbc[3] * domain->yz; - dz = pbc[2] * domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = radius[j]; - buf[m++] = vfrac[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; // 8 - - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; // 11 - buf[m++] = e[j]; // 12 - - } - } else { - dvx = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; - dvy = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; - dvz = pbc[2] * h_rate[2]; -// printf("\ndvx = %f, dvy=%f, dvz=%f\n", dvx, dvy, dvz); -// printf("dx = %f, dy=%f, dz=%f\n", dx, dy, dz); - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = radius[j]; - buf[m++] = vfrac[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - buf[m++] = vest[j][0] + dvx; - buf[m++] = vest[j][1] + dvy; - buf[m++] = vest[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; // 8 - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; // 11 - } - - buf[m++] = e[j]; // 12 - - } - } - } - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_comm_hybrid(int n, int *list, double *buf) { - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = radius[j]; - buf[m++] = vfrac[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - buf[m++] = e[j]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSMD::unpack_comm(int /*n*/, int /*first*/, double * /*buf*/) { - error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSMD::unpack_comm_vel(int n, int first, double *buf) { - int i, m, last; - - 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++]; //3 - radius[i] = buf[m++]; - vfrac[i] = buf[m++]; // 5 - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; // 8 - - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; // 11 - e[i] = buf[m++]; - - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::unpack_comm_hybrid(int n, int first, double *buf) { - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - radius[i] = buf[m++]; - vfrac[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - e[i] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_reverse(int n, int first, double *buf) { - int i, m, last; - - printf("in pack_reverse\n"); - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = de[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_reverse_hybrid(int n, int first, double *buf) { - int i, m, last; + initialize non-zero atom quantities +------------------------------------------------------------------------- */ - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = de[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSMD::unpack_reverse(int n, int *list, double *buf) { - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - de[j] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::unpack_reverse_hybrid(int n, int *list, double *buf) { - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - de[j] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_border(int /*n*/, int * /*list*/, double * /*buf*/, int /*pbc_flag*/, int * /*pbc*/) { - error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); - return -1; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_border_vel(int n, int *list, double *buf, int pbc_flag, int *pbc) { - int i, j, m; - double dx, dy, dz, dvx, dvy, dvz; - - //printf("AtomVecSMD::pack_border_vel\n"); - - m = 0; - if (pbc_flag == 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]; // 3 - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; // 6 - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; // 10 - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = vfrac[j]; - buf[m++] = contact_radius[j]; - buf[m++] = e[j]; - buf[m++] = eff_plastic_strain[j]; // 16 - - for (int k = 0; k < NMAT_FULL; k++) { - buf[m++] = smd_data_9[j][k]; - } // 25 - - for (int k = 0; k < NMAT_SYMM; k++) { - buf[m++] = tlsph_stress[j][k]; - } // 31 - - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; // 34 - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; // 37 - } - } else { - - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - //printf("dx = %f\n", dx); - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; // 3 - buf[m++] = x0[j][0]; // this is correct - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; // 6 - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; // 10 - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = vfrac[j]; - buf[m++] = contact_radius[j]; - buf[m++] = e[j]; - buf[m++] = eff_plastic_strain[j]; // 17 - - for (int k = 0; k < NMAT_FULL; k++) { - buf[m++] = smd_data_9[j][k]; - } // 26 - - for (int k = 0; k < NMAT_SYMM; k++) { - buf[m++] = tlsph_stress[j][k]; - } // 32 - - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; // 35 - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; // 38 - - } - } else { - dvx = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; - dvy = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; - dvz = pbc[2] * h_rate[2]; -// printf("\ndvx = %f, dvy=%f, dvz=%f\n", dvx, dvy, dvz); -// printf("dx = %f, dy=%f, dz=%f\n", dx, dy, dz); - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; // 3 - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; // 6 - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = ubuf(molecule[j]).d; // 10 - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = vfrac[j]; - buf[m++] = contact_radius[j]; - buf[m++] = e[j]; - buf[m++] = eff_plastic_strain[j]; // 16 - - for (int k = 0; k < NMAT_FULL; k++) { - buf[m++] = smd_data_9[j][k]; - } // 25 - - for (int k = 0; k < NMAT_SYMM; k++) { - buf[m++] = tlsph_stress[j][k]; - } // 31 - - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; // 34 - buf[m++] = vest[j][0] + dvx; - buf[m++] = vest[j][1] + dvy; - buf[m++] = vest[j][2] + dvz; // 37 - - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; // 34 - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; // 37 - } - - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n, list, &buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::pack_border_hybrid(int n, int *list, double *buf) { - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - - buf[m++] = x0[j][0]; - buf[m++] = x0[j][1]; - buf[m++] = x0[j][2]; // 3 - buf[m++] = ubuf(molecule[j]).d; // 4 - buf[m++] = radius[j]; - buf[m++] = rmass[j]; - buf[m++] = vfrac[j]; - buf[m++] = contact_radius[j]; - buf[m++] = e[j]; - buf[m++] = eff_plastic_strain[j]; // 11 - - for (int k = 0; k < NMAT_FULL; k++) { - buf[m++] = smd_data_9[j][k]; - } // 20 +void AtomVecSMD::create_atom_post(int ilocal) +{ + atom->x0[ilocal][0] = atom->x[ilocal][0]; + atom->x0[ilocal][1] = atom->x[ilocal][1]; + atom->x0[ilocal][2] = atom->x[ilocal][2]; - for (int k = 0; k < NMAT_SYMM; k++) { - buf[m++] = tlsph_stress[j][k]; - } // 26 - - } - return m; + atom->vfrac[ilocal] = 1.0; + atom->rmass[ilocal] = 1.0; + atom->radius[ilocal] = 0.5; + atom->contact_radius[ilocal] = 0.5; + atom->molecule[ilocal] = 1; + + atom->smd_data_9[ilocal][0] = 1.0; // xx + atom->smd_data_9[ilocal][4] = 1.0; // yy + atom->smd_data_9[ilocal][8] = 1.0; // zz } -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities +------------------------------------------------------------------------- */ + +void AtomVecSMD::data_atom_post(int ilocal) +{ + atom->e[ilocal] = 0.0; + atom->x0[ilocal][0] = atom->x[ilocal][0]; + atom->x0[ilocal][1] = atom->x[ilocal][1]; + atom->x0[ilocal][2] = atom->x[ilocal][2]; + + atom->vest[ilocal][0] = 0.0; + atom->vest[ilocal][1] = 0.0; + atom->vest[ilocal][2] = 0.0; + + atom->damage[ilocal] = 0.0; -void AtomVecSMD::unpack_border(int /*n*/, int /*first*/, double * /*buf*/) { - error->one(FLERR, "atom vec tlsph can only be used with ghost velocities turned on"); -} - -/* ---------------------------------------------------------------------- */ + atom->eff_plastic_strain[ilocal] = 0.0; + atom->eff_plastic_strain_rate[ilocal] = 0.0; -void AtomVecSMD::unpack_border_vel(int n, int first, double *buf) { - int i, m, last; + for (int k = 0; k < NMAT_FULL; k++) + atom->smd_data_9[ilocal][k] = 0.0; - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) - grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; // 3 - x0[i][0] = buf[m++]; - x0[i][1] = buf[m++]; - x0[i][2] = buf[m++]; // 6 - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - molecule[i] = (tagint) ubuf(buf[m++]).i; // 10 + for (int k = 0; k < NMAT_SYMM; k++) + atom->smd_stress[ilocal][k] = 0.0; - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - vfrac[i] = buf[m++]; - contact_radius[i] = buf[m++]; - e[i] = buf[m++]; - eff_plastic_strain[i] = buf[m++]; // 16 - - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[i][k] = buf[m++]; - } // 25 - - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[i][k] = buf[m++]; - } // 31 - - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; // 34 - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; // 37 - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->unpack_border(n, first, &buf[m]); + atom->smd_data_9[ilocal][0] = 1.0; // xx + atom->smd_data_9[ilocal][4] = 1.0; // yy + atom->smd_data_9[ilocal][8] = 1.0; // zz } -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::unpack_border_hybrid(int n, int first, double *buf) { - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - x0[i][0] = buf[m++]; - x0[i][1] = buf[m++]; - x0[i][2] = buf[m++]; // 3 - molecule[i] = (tagint) ubuf(buf[m++]).i; // 4 - radius[i] = buf[m++]; - rmass[i] = buf[m++]; - vfrac[i] = buf[m++]; - contact_radius[i] = buf[m++]; - e[i] = buf[m++]; - eff_plastic_strain[i] = buf[m++]; // 11 - - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[i][k] = buf[m++]; - } // 20 - - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[i][k] = buf[m++]; - } // 26 - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them - ------------------------------------------------------------------------- */ - -int AtomVecSMD::pack_exchange(int i, double *buf) { - int m = 1; - - //printf("in AtomVecSMD::pack_exchange tag %d\n", tag[i]); - - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; // 3 - buf[m++] = x0[i][0]; - buf[m++] = x0[i][1]; - buf[m++] = x0[i][2]; // 6 - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = ubuf(molecule[i]).d; // 11 - buf[m++] = radius[i]; - buf[m++] = rmass[i]; - buf[m++] = vfrac[i]; - buf[m++] = contact_radius[i]; - buf[m++] = e[i]; - buf[m++] = eff_plastic_strain[i]; // 18 - buf[m++] = eff_plastic_strain_rate[i]; // 19 - - for (int k = 0; k < NMAT_FULL; k++) { - buf[m++] = smd_data_9[i][k]; - } // 27 - - for (int k = 0; k < NMAT_SYMM; k++) { - buf[m++] = tlsph_stress[i][k]; - } // 33 - - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; // 36 - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; // 39 - - buf[m++] = damage[i]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i, &buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecSMD::unpack_exchange(double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) - grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; // 3 - x0[nlocal][0] = buf[m++]; - x0[nlocal][1] = buf[m++]; - x0[nlocal][2] = buf[m++]; // 6 - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; // 11 - radius[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - vfrac[nlocal] = buf[m++]; - contact_radius[nlocal] = buf[m++]; - e[nlocal] = buf[m++]; - eff_plastic_strain[nlocal] = buf[m++]; // 18 - eff_plastic_strain_rate[nlocal] = buf[m++]; // 19 - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[nlocal][k] = buf[m++]; - } // 27 - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[nlocal][k] = buf[m++]; - } // 33 - - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; // 36 - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; // 39 - - damage[nlocal] = buf[m++]; //40 - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->unpack_exchange(nlocal, &buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes - ------------------------------------------------------------------------- */ - -int AtomVecSMD::size_restart() { - int i; - - int nlocal = atom->nlocal; - int n = 43 * nlocal; // count pack_restart + 1 (size of buffer) - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive - ------------------------------------------------------------------------- */ -int AtomVecSMD::pack_restart(int i, double *buf) { - int m = 1; // 1 - - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; // 4 - buf[m++] = x0[i][0]; - buf[m++] = x0[i][1]; - buf[m++] = x0[i][2]; // 7 - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; // 10 - buf[m++] = ubuf(image[i]).d; - buf[m++] = ubuf(molecule[i]).d; - buf[m++] = radius[i]; - buf[m++] = rmass[i]; - buf[m++] = vfrac[i]; // 15 - buf[m++] = contact_radius[i]; - buf[m++] = e[i]; - buf[m++] = eff_plastic_strain[i]; - buf[m++] = eff_plastic_strain_rate[i]; // 19 - - for (int k = 0; k < NMAT_FULL; k++) { - buf[m++] = smd_data_9[i][k]; - } // 28 - - for (int k = 0; k < NMAT_SYMM; k++) { - buf[m++] = tlsph_stress[i][k]; - } // 34 - - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; // 37 - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; // 40 - - buf[m++] = damage[i]; // 41 - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i, &buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - ------------------------------------------------------------------------- */ - -int AtomVecSMD::unpack_restart(double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra, nmax, atom->nextra_store, "atom:extra"); - } - - int m = 1; - - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; // 3 - x0[nlocal][0] = buf[m++]; - x0[nlocal][1] = buf[m++]; - x0[nlocal][2] = buf[m++]; // 6 - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - molecule[nlocal] = (tagint) ubuf(buf[m++]).i; // 11 - - radius[nlocal] = buf[m++]; - rmass[nlocal] = buf[m++]; - vfrac[nlocal] = buf[m++]; //14 - contact_radius[nlocal] = buf[m++]; //15 - e[nlocal] = buf[m++]; - eff_plastic_strain[nlocal] = buf[m++]; // 18 - eff_plastic_strain_rate[nlocal] = buf[m++]; // 29 - - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[nlocal][k] = buf[m++]; - } // 28 - - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[nlocal][k] = buf[m++]; - } // 34 - - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; // 37 - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; // 40 - - damage[nlocal] = buf[m++]; //41 - - //printf("nlocal in restart is %d\n", nlocal); - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast(buf[0]) - m; - for (int i = 0; i < size; i++) - extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - - //printf("returning m=%d in unpack_restart\n", m); - - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults - ------------------------------------------------------------------------- */ - -void AtomVecSMD::create_atom(int itype, double *coord) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - printf("nlocal = %d, nmax = %d, calling grow\n", nlocal, nmax); - grow(0); - printf("... finished growing\n"); - } - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - x0[nlocal][0] = coord[0]; - x0[nlocal][1] = coord[1]; - x0[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - - vfrac[nlocal] = 1.0; - rmass[nlocal] = 1.0; - radius[nlocal] = 0.5; - contact_radius[nlocal] = 0.5; - molecule[nlocal] = 1; - e[nlocal] = 0.0; - eff_plastic_strain[nlocal] = 0.0; - eff_plastic_strain_rate[nlocal] = 0.0; - - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[nlocal][k] = 0.0; - } - smd_data_9[nlocal][0] = 1.0; // xx - smd_data_9[nlocal][4] = 1.0; // yy - smd_data_9[nlocal][8] = 1.0; // zz - - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[nlocal][k] = 0.0; - } - - damage[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities - ------------------------------------------------------------------------- */ - -void AtomVecSMD::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) - grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR, "Invalid atom type in Atoms section of data file"); - - molecule[nlocal] = utils::tnumeric(FLERR,values[2],true,lmp); - if (molecule[nlocal] <= 0) - error->one(FLERR, "Invalid molecule in Atoms section of data file"); - - vfrac[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - if (vfrac[nlocal] < 0.0) - error->one(FLERR, "Invalid volume in Atoms section of data file"); - - rmass[nlocal] = utils::numeric(FLERR,values[4],true,lmp); - if (rmass[nlocal] == 0.0) - error->one(FLERR, "Invalid mass in Atoms section of data file"); - - radius[nlocal] = utils::numeric(FLERR,values[5],true,lmp); - if (radius[nlocal] < 0.0) - error->one(FLERR, "Invalid radius in Atoms section of data file"); - - contact_radius[nlocal] = utils::numeric(FLERR,values[6],true,lmp); - if (contact_radius[nlocal] < 0.0) - error->one(FLERR, "Invalid contact radius in Atoms section of data file"); - - e[nlocal] = 0.0; - - x0[nlocal][0] = utils::numeric(FLERR,values[7],true,lmp); - x0[nlocal][1] = utils::numeric(FLERR,values[8],true,lmp); - x0[nlocal][2] = utils::numeric(FLERR,values[9],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - - damage[nlocal] = 0.0; - - eff_plastic_strain[nlocal] = 0.0; - eff_plastic_strain_rate[nlocal] = 0.0; - - for (int k = 0; k < NMAT_FULL; k++) { - smd_data_9[nlocal][k] = 0.0; - } - - for (int k = 0; k < NMAT_SYMM; k++) { - tlsph_stress[nlocal][k] = 0.0; - } - - smd_data_9[nlocal][0] = 1.0; // xx - smd_data_9[nlocal][4] = 1.0; // yy - smd_data_9[nlocal][8] = 1.0; // zz - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style - ------------------------------------------------------------------------- */ - -int AtomVecSMD::data_atom_hybrid(int /*nlocal*/, char **/*values*/) { - error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style smd"); - return -1; -} - -/* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file - ------------------------------------------------------------------------- */ - -void AtomVecSMD::data_vel(int m, char **values) { - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - vest[m][0] = utils::numeric(FLERR,values[0],true,lmp); - vest[m][1] = utils::numeric(FLERR,values[1],true,lmp); - vest[m][2] = utils::numeric(FLERR,values[2],true,lmp); -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file - ------------------------------------------------------------------------- */ - -int AtomVecSMD::data_vel_hybrid(int /*m*/, char **/*values*/) { - error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style smd"); - return 0; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags - ------------------------------------------------------------------------- */ - -void AtomVecSMD::pack_data(double **buf) { - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = ubuf(molecule[i]).d; - buf[i][3] = vfrac[i]; - buf[i][4] = rmass[i]; - buf[i][5] = radius[i]; - buf[i][6] = contact_radius[i]; - - buf[i][7] = x[i][0]; - buf[i][8] = x[i][1]; - buf[i][9] = x[i][2]; - - buf[i][10] = x0[i][0]; - buf[i][11] = x0[i][1]; - buf[i][12] = x0[i][2]; - - buf[i][13] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][14] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][15] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file - ------------------------------------------------------------------------- */ - -int AtomVecSMD::pack_data_hybrid(int /*i*/, double * /*buf*/) { - error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style smd"); - return -1; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags - ------------------------------------------------------------------------- */ - -void AtomVecSMD::write_data(FILE *fp, int n, double **buf) { - for (int i = 0; i < n; i++) - fprintf(fp, - TAGINT_FORMAT - " %d %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e\n", (tagint) ubuf(buf[i][0]).i, - (int) ubuf(buf[i][1]).i, (int) ubuf(buf[i][2]).i, buf[i][3], buf[i][4], buf[i][5], buf[i][6], buf[i][7], buf[i][8], - buf[i][9], buf[i][10], buf[i][11], buf[i][12]); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file - ------------------------------------------------------------------------- */ - -int AtomVecSMD::write_data_hybrid(FILE * /*fp*/, double * /*buf*/) { - error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style smd"); - return -1; -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file - ------------------------------------------------------------------------- */ - -void AtomVecSMD::pack_vel(double **buf) { - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid velocity info for data file - ------------------------------------------------------------------------- */ - -int AtomVecSMD::pack_vel_hybrid(int /*i*/, double * /*buf*/) { - error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style smd"); - return 0; -} - -/* ---------------------------------------------------------------------- - write velocity info to data file - ------------------------------------------------------------------------- */ - -void AtomVecSMD::write_vel(FILE *fp, int n, double **buf) { - for (int i = 0; i < n; i++) - fprintf(fp, TAGINT_FORMAT - " %-1.16e %-1.16e %-1.16e\n", (tagint) ubuf(buf[i][0]).i, buf[i][1], buf[i][2], buf[i][3]); -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file - ------------------------------------------------------------------------- */ - -int AtomVecSMD::write_vel_hybrid(FILE * /*fp*/, double * /*buf*/) { - error->one(FLERR, "hybrid atom style functionality not yet implemented for atom style smd"); - return 3; -} - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory - ------------------------------------------------------------------------- */ - -bigint AtomVecSMD::memory_usage() { - bigint bytes = 0; - - if (atom->memcheck("tag")) - bytes += memory->usage(tag, nmax); - if (atom->memcheck("type")) - bytes += memory->usage(type, nmax); - if (atom->memcheck("molecule")) - bytes += memory->usage(molecule, nmax); - if (atom->memcheck("mask")) - bytes += memory->usage(mask, nmax); - if (atom->memcheck("image")) - bytes += memory->usage(image, nmax); - if (atom->memcheck("x")) - bytes += memory->usage(x, nmax, 3); - if (atom->memcheck("v")) - bytes += memory->usage(v, nmax, 3); - if (atom->memcheck("vest")) - bytes += memory->usage(vest, nmax, 3); - if (atom->memcheck("f")) - bytes += memory->usage(f, nmax * comm->nthreads, 3); - - if (atom->memcheck("radius")) - bytes += memory->usage(radius, nmax); - if (atom->memcheck("contact_radius")) - bytes += memory->usage(contact_radius, nmax); - if (atom->memcheck("vfrac")) - bytes += memory->usage(vfrac, nmax); - if (atom->memcheck("rmass")) - bytes += memory->usage(rmass, nmax); - if (atom->memcheck("eff_plastic_strain")) - bytes += memory->usage(eff_plastic_strain, nmax); - if (atom->memcheck("eff_plastic_strain_rate")) - bytes += memory->usage(eff_plastic_strain_rate, nmax); - if (atom->memcheck("e")) - bytes += memory->usage(e, nmax); - if (atom->memcheck("de")) - bytes += memory->usage(de, nmax); - - if (atom->memcheck("smd_data_9")) - bytes += memory->usage(smd_data_9, nmax, NMAT_FULL); - if (atom->memcheck("tlsph_stress")) - bytes += memory->usage(tlsph_stress, nmax, NMAT_SYMM); - - if (atom->memcheck("damage")) - bytes += memory->usage(damage, nmax); - - return bytes; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecSMD::force_clear(int n, size_t nbytes) { - //printf("clearing force on atom %d", n); - memset(&de[n], 0, nbytes); - memset(&f[0][0], 0, 3 * nbytes); -} diff --git a/src/USER-SMD/atom_vec_smd.h b/src/USER-SMD/atom_vec_smd.h index 34fdfc1f76..539f209ca7 100644 --- a/src/USER-SMD/atom_vec_smd.h +++ b/src/USER-SMD/atom_vec_smd.h @@ -9,7 +9,6 @@ * * ----------------------------------------------------------------------- */ - /* ---------------------------------------------------------------------- LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator http://lammps.sandia.gov, Sandia National Laboratories @@ -39,63 +38,9 @@ namespace LAMMPS_NS { class AtomVecSMD : public AtomVec { public: AtomVecSMD(class LAMMPS *); - ~AtomVecSMD() {} - void init(); - void grow(int); - void grow_reset(); - void copy(int, int, int); void force_clear(int, size_t); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); - bigint memory_usage(); - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *radius,*rmass; - - tagint *molecule; - double *vfrac,**x0,*contact_radius, **smd_data_9, *e, *de, **vest; - double **tlsph_stress; - double *eff_plastic_strain; - double *damage; - double *eff_plastic_strain_rate; - - + void create_atom_post(int); + void data_atom_post(int); }; } diff --git a/src/USER-SPH/atom_vec_meso.cpp b/src/USER-SPH/atom_vec_meso.cpp index cd7c2251ab..a80ab91d2e 100644 --- a/src/USER-SPH/atom_vec_meso.cpp +++ b/src/USER-SPH/atom_vec_meso.cpp @@ -14,13 +14,7 @@ #include "atom_vec_meso.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -32,921 +26,64 @@ AtomVecMeso::AtomVecMeso(LAMMPS *lmp) : AtomVec(lmp) mass_type = 1; forceclearflag = 1; - comm_x_only = 0; // we communicate not only x forward but also vest ... - comm_f_only = 0; // we also communicate de and drho in reverse direction - size_forward = 8; // 3 + rho + e + vest[3], that means we may only communicate 5 in hybrid - size_reverse = 5; // 3 + drho + de - size_border = 12; // 6 + rho + e + vest[3] + cv - size_velocity = 3; - size_data_atom = 8; - size_data_vel = 4; - xcol_data = 6; - atom->e_flag = 1; atom->rho_flag = 1; atom->cv_flag = 1; atom->vest_flag = 1; -} -/* ---------------------------------------------------------------------- - grow atom arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n - ------------------------------------------------------------------------- */ + // 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 -void AtomVecMeso::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - if (nmax < 0 || nmax > MAXSMALLINT) - error->one(FLERR,"Per-processor system is too big"); + fields_grow = (char *) "rho drho e de cv vest"; + fields_copy = (char *) "rho drho e de cv vest"; + fields_comm = (char *) "rho e vest"; + fields_comm_vel = (char *) "rho e vest"; + fields_reverse = (char *) "drho de"; + fields_border = (char *) "rho e cv vest"; + fields_border_vel = (char *) "rho e cv vest"; + fields_exchange = (char *) "rho e cv vest"; + fields_restart = (char * ) "rho e cv vest"; + fields_create = (char *) "rho e cv vest de drho"; + fields_data_atom = (char *) "id type rho e cv x"; + fields_data_vel = (char *) "id v"; - tag = memory->grow(atom->tag, nmax, "atom:tag"); - type = memory->grow(atom->type, nmax, "atom:type"); - mask = memory->grow(atom->mask, nmax, "atom:mask"); - image = memory->grow(atom->image, nmax, "atom:image"); - x = memory->grow(atom->x, nmax, 3, "atom:x"); - v = memory->grow(atom->v, nmax, 3, "atom:v"); - f = memory->grow(atom->f, nmax*comm->nthreads, 3, "atom:f"); - - rho = memory->grow(atom->rho, nmax, "atom:rho"); - drho = memory->grow(atom->drho, nmax*comm->nthreads, "atom:drho"); - e = memory->grow(atom->e, nmax, "atom:e"); - de = memory->grow(atom->de, nmax*comm->nthreads, "atom:de"); - vest = memory->grow(atom->vest, nmax, 3, "atom:vest"); - cv = memory->grow(atom->cv, nmax, "atom:cv"); - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); + setup_fields(); } /* ---------------------------------------------------------------------- - reset local array ptrs - ------------------------------------------------------------------------- */ - -void AtomVecMeso::grow_reset() { - tag = atom->tag; - type = atom->type; - mask = atom->mask; - image = atom->image; - x = atom->x; - v = atom->v; - f = atom->f; - rho = atom->rho; - drho = atom->drho; - e = atom->e; - de = atom->de; - vest = atom->vest; - cv = atom->cv; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::copy(int i, int j, int delflag) { - //printf("in AtomVecMeso::copy\n"); - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - rho[j] = rho[i]; - drho[j] = drho[i]; - e[j] = e[i]; - de[j] = de[i]; - cv[j] = cv[i]; - vest[j][0] = vest[i][0]; - vest[j][1] = vest[i][1]; - vest[j][2] = vest[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i, j,delflag); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::force_clear(int n, size_t nbytes) -{ - memset(&de[n],0,nbytes); - memset(&drho[n],0,nbytes); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_comm_hybrid(int n, int *list, double *buf) { - //printf("in AtomVecMeso::pack_comm_hybrid\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::unpack_comm_hybrid(int n, int first, double *buf) { - //printf("in AtomVecMeso::unpack_comm_hybrid\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - rho[i] = buf[m++]; - e[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_border_hybrid(int n, int *list, double *buf) { - //printf("in AtomVecMeso::pack_border_hybrid\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::unpack_border_hybrid(int n, int first, double *buf) { - //printf("in AtomVecMeso::unpack_border_hybrid\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - rho[i] = buf[m++]; - e[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_reverse_hybrid(int n, int first, double *buf) { - //printf("in AtomVecMeso::pack_reverse_hybrid\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = drho[i]; - buf[m++] = de[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::unpack_reverse_hybrid(int n, int *list, double *buf) { - //printf("in AtomVecMeso::unpack_reverse_hybrid\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - drho[j] += buf[m++]; - de[j] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_comm(int n, int *list, double *buf, int pbc_flag, - int *pbc) { - //printf("in AtomVecMeso::pack_comm\n"); - int i, j, m; - double dx, dy, dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0] * domain->xprd + pbc[5] * domain->xy + pbc[4] * domain->xz; - dy = pbc[1] * domain->yprd + pbc[3] * domain->yz; - dz = pbc[2] * domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_comm_vel(int n, int *list, double *buf, int pbc_flag, - int *pbc) { - //printf("in AtomVecMeso::pack_comm_vel\n"); - int i, j, m; - double dx, dy, dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0] * domain->xprd + pbc[5] * domain->xy + pbc[4] * domain->xz; - dy = pbc[1] * domain->yprd + pbc[3] * domain->yz; - dz = pbc[2] * domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::unpack_comm(int n, int first, double *buf) { - //printf("in AtomVecMeso::unpack_comm\n"); - int i, m, last; - - 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++]; - rho[i] = buf[m++]; - e[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::unpack_comm_vel(int n, int first, double *buf) { - //printf("in AtomVecMeso::unpack_comm_vel\n"); - int i, m, last; - - 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++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - rho[i] = buf[m++]; - e[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_reverse(int n, int first, double *buf) { - //printf("in AtomVecMeso::pack_reverse\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = drho[i]; - buf[m++] = de[i]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::unpack_reverse(int n, int *list, double *buf) { - //printf("in AtomVecMeso::unpack_reverse\n"); - int i, j, m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - drho[j] += buf[m++]; - de[j] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_border(int n, int *list, double *buf, int pbc_flag, - int *pbc) { - //printf("in AtomVecMeso::pack_border\n"); - int i, j, m; - double dx, dy, dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = cv[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = cv[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::pack_border_vel(int n, int *list, double *buf, int pbc_flag, - int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = cv[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0] * domain->xprd; - dy = pbc[1] * domain->yprd; - dz = pbc[2] * domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = cv[j]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - } else { - dvx = pbc[0] * h_rate[0] + pbc[5] * h_rate[5] + pbc[4] * h_rate[4]; - dvy = pbc[1] * h_rate[1] + pbc[3] * h_rate[3]; - dvz = pbc[2] * h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - buf[m++] = vest[j][0] + dvx; - buf[m++] = vest[j][1] + dvy; - buf[m++] = vest[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - buf[m++] = vest[j][0]; - buf[m++] = vest[j][1]; - buf[m++] = vest[j][2]; - } - buf[m++] = rho[j]; - buf[m++] = e[j]; - buf[m++] = cv[j]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::unpack_border(int n, int first, double *buf) { - //printf("in AtomVecMeso::unpack_border\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) - grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - rho[i] = buf[m++]; - e[i] = buf[m++]; - cv[i] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecMeso::unpack_border_vel(int n, int first, double *buf) { - //printf("in AtomVecMeso::unpack_border_vel\n"); - int i, m, last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) - grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - vest[i][0] = buf[m++]; - vest[i][1] = buf[m++]; - vest[i][2] = buf[m++]; - rho[i] = buf[m++]; - e[i] = buf[m++]; - cv[i] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them - ------------------------------------------------------------------------- */ - -int AtomVecMeso::pack_exchange(int i, double *buf) { - //printf("in AtomVecMeso::pack_exchange\n"); - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = rho[i]; - buf[m++] = e[i]; - buf[m++] = cv[i]; - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i, &buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecMeso::unpack_exchange(double *buf) { - //printf("in AtomVecMeso::unpack_exchange\n"); - int nlocal = atom->nlocal; - if (nlocal == nmax) - grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - rho[nlocal] = buf[m++]; - e[nlocal] = buf[m++]; - cv[nlocal] = buf[m++]; - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> unpack_exchange(nlocal, - &buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes - ------------------------------------------------------------------------- */ - -int AtomVecMeso::size_restart() { - int i; - - int nlocal = atom->nlocal; - int n = 17 * nlocal; // 11 + rho + e + cv + vest[3] - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive - ------------------------------------------------------------------------- */ - -int AtomVecMeso::pack_restart(int i, double *buf) { - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = rho[i]; - buf[m++] = e[i]; - buf[m++] = cv[i]; - buf[m++] = vest[i][0]; - buf[m++] = vest[i][1]; - buf[m++] = vest[i][2]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i, &buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities - ------------------------------------------------------------------------- */ - -int AtomVecMeso::unpack_restart(double *buf) { - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra, nmax, atom->nextra_store, "atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - rho[nlocal] = buf[m++]; - e[nlocal] = buf[m++]; - cv[nlocal] = buf[m++]; - vest[nlocal][0] = buf[m++]; - vest[nlocal][1] = buf[m++]; - vest[nlocal][2] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) - extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults - ------------------------------------------------------------------------- */ - -void AtomVecMeso::create_atom(int itype, double *coord) { - int nlocal = atom->nlocal; - if (nlocal == nmax) - grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - rho[nlocal] = 0.0; - e[nlocal] = 0.0; - cv[nlocal] = 1.0; - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - de[nlocal] = 0.0; - drho[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities - ------------------------------------------------------------------------- */ - -void AtomVecMeso::data_atom(double *coord, imageint imagetmp, char **values) { - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - rho[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - e[nlocal] = utils::numeric(FLERR,values[3],true,lmp); - cv[nlocal] = utils::numeric(FLERR,values[4],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - //printf("rho=%f, e=%f, cv=%f, x=%f\n", rho[nlocal], e[nlocal], cv[nlocal], x[nlocal][0]); - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - vest[nlocal][0] = 0.0; - vest[nlocal][1] = 0.0; - vest[nlocal][2] = 0.0; - - de[nlocal] = 0.0; - drho[nlocal] = 0.0; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style - ------------------------------------------------------------------------- */ - -int AtomVecMeso::data_atom_hybrid(int nlocal, char **values) { - - rho[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - e[nlocal] = utils::numeric(FLERR,values[1],true,lmp); - cv[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - - return 3; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector ------------------------------------------------------------------------- */ -void AtomVecMeso::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = rho[i]; - buf[i][3] = e[i]; - buf[i][4] = cv[i]; - buf[i][5] = x[i][0]; - buf[i][6] = x[i][1]; - buf[i][7] = x[i][2]; - buf[i][8] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][9] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][10] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecMeso::pack_data_hybrid(int i, double *buf) +void AtomVecMeso::force_clear(int n, size_t nbytes) { - buf[0] = rho[i]; - buf[1] = e[i]; - buf[2] = cv[i]; - return 3; + memset(&atom->de[n],0,nbytes); + memset(&atom->drho[n],0,nbytes); } /* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags + initialize non-zero atom quantities ------------------------------------------------------------------------- */ -void AtomVecMeso::write_data(FILE *fp, int n, double **buf) +void AtomVecMeso::create_atom_post(int ilocal) { - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e %-1.16e " - "%d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],buf[i][3],buf[i][4], - buf[i][5],buf[i][6],buf[i][7], - (int) ubuf(buf[i][8]).i,(int) ubuf(buf[i][9]).i, - (int) ubuf(buf[i][10]).i); + atom->cv[ilocal] = 1.0; } /* ---------------------------------------------------------------------- - write hybrid atom info to data file + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -int AtomVecMeso::write_data_hybrid(FILE *fp, double *buf) +void AtomVecMeso::data_atom_post(int ilocal) { - fprintf(fp," %-1.16e %-1.16e %-1.16e",buf[0],buf[1],buf[2]); - return 3; + atom->vest[ilocal][0] = 0.0; + atom->vest[ilocal][1] = 0.0; + atom->vest[ilocal][2] = 0.0; + atom->de[ilocal] = 0.0; + atom->drho[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -977,30 +114,35 @@ void AtomVecMeso::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { + double *rho = atom->rho; 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 == 1) { + double *drho = atom->drho; 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 == 2) { + double *e = atom->e; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = e[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 3) { + double *de = atom->de; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = de[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 4) { + double *cv = atom->cv; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = cv[i]; else buf[n] = 0.0; @@ -1008,40 +150,3 @@ void AtomVecMeso::pack_property_atom(int index, double *buf, } } } - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory - ------------------------------------------------------------------------- */ - -bigint AtomVecMeso::memory_usage() { - bigint bytes = 0; - - if (atom->memcheck("tag")) - bytes += memory->usage(tag, nmax); - if (atom->memcheck("type")) - bytes += memory->usage(type, nmax); - if (atom->memcheck("mask")) - bytes += memory->usage(mask, nmax); - if (atom->memcheck("image")) - bytes += memory->usage(image, nmax); - if (atom->memcheck("x")) - bytes += memory->usage(x, nmax, 3); - if (atom->memcheck("v")) - bytes += memory->usage(v, nmax, 3); - if (atom->memcheck("f")) - bytes += memory->usage(f, nmax*comm->nthreads, 3); - if (atom->memcheck("rho")) - bytes += memory->usage(rho, nmax); - if (atom->memcheck("drho")) - bytes += memory->usage(drho, nmax*comm->nthreads); - if (atom->memcheck("e")) - bytes += memory->usage(e, nmax); - if (atom->memcheck("de")) - bytes += memory->usage(de, nmax*comm->nthreads); - if (atom->memcheck("cv")) - bytes += memory->usage(cv, nmax); - if (atom->memcheck("vest")) - bytes += memory->usage(vest, nmax); - - return bytes; -} diff --git a/src/USER-SPH/atom_vec_meso.h b/src/USER-SPH/atom_vec_meso.h index da68222e29..c8a1090474 100644 --- a/src/USER-SPH/atom_vec_meso.h +++ b/src/USER-SPH/atom_vec_meso.h @@ -27,50 +27,11 @@ namespace LAMMPS_NS { class AtomVecMeso : public AtomVec { public: AtomVecMeso(class LAMMPS *); - ~AtomVecMeso() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); void force_clear(int, size_t); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); - int pack_comm_hybrid(int, int *, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_border_hybrid(int, int *, double *); - int unpack_border_hybrid(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); + void create_atom_post(int); + void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); - bigint memory_usage(); - - private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - double *rho, *drho, *e, *de, *cv; - double **vest; // estimated velocity during force computation }; } diff --git a/src/atom.cpp b/src/atom.cpp index d238db5e65..8fd859478f 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -81,50 +81,21 @@ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) image = NULL; x = v = f = NULL; - molecule = NULL; - molindex = molatom = NULL; + // charged and dipolar particles + q = NULL; mu = NULL; + + // finite-size particles + omega = angmom = torque = NULL; radius = rmass = NULL; ellipsoid = line = tri = body = NULL; - vfrac = s0 = NULL; - x0 = NULL; - - spin = NULL; - eradius = ervel = erforce = NULL; - cs = csforce = vforce = ervelforce = NULL; - etag = NULL; - - rho = drho = e = de = cv = NULL; - vest = NULL; - - // SPIN package - - sp = fm = fm_long = NULL; + // molecular systems - // USER-DPD - - uCond = uMech = uChem = uCG = uCGnew = NULL; - duChem = NULL; - dpdTheta = NULL; - - // USER-MESO - - cc = cc_flux = NULL; - edpd_temp = edpd_flux = edpd_cv = NULL; - - // USER-SMD - - contact_radius = NULL; - smd_data_9 = NULL; - smd_stress = NULL; - eff_plastic_strain = NULL; - eff_plastic_strain_rate = NULL; - damage = NULL; - - // molecular info + molecule = NULL; + molindex = molatom = NULL; bond_per_atom = extra_bond_per_atom = 0; num_bond = NULL; @@ -150,6 +121,47 @@ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) nspecial = NULL; special = NULL; + // PERI package + + vfrac = s0 = NULL; + x0 = NULL; + + // SPIN package + + sp = fm = fm_long = NULL; + + // USER-EFF and USER-AWPMD packages + + spin = NULL; + eradius = ervel = erforce = NULL; + ervelforce = cs = csforce = NULL; + vforce = NULL; + etag = NULL; + + // USER-DPD package + + uCond = uMech = uChem = uCG = uCGnew = NULL; + duChem = dpdTheta = NULL; + + // USER-MESO package + + cc = cc_flux = NULL; + edpd_temp = edpd_flux = edpd_cv = NULL; + + // USER-SMD package + + contact_radius = NULL; + smd_data_9 = NULL; + smd_stress = NULL; + eff_plastic_strain = NULL; + eff_plastic_strain_rate = NULL; + damage = NULL; + + // USER-SPH package + + rho = drho = e = de = cv = NULL; + vest = NULL; + // user-defined molecules nmolecule = 0; @@ -532,9 +544,16 @@ void Atom::peratom_create() add_peratom("ervel",&ervel,DOUBLE,0); add_peratom("erforce",&erforce,DOUBLE,0,1); // set per-thread flag + // USER-AWPMD package + + add_peratom("cs",&cs,DOUBLE,0); + add_peratom("csforce",&csforce,DOUBLE,0); + add_peratom("vforce",&vforce,DOUBLE,3); + add_peratom("ervelforce",&ervelforce,DOUBLE,0); + add_peratom("etag",&etag,INT,0); + // USER-DPD package - add_peratom("rho",&eradius,DOUBLE,0); add_peratom("dpdTheta",&dpdTheta,DOUBLE,0); add_peratom("uCond",&uCond,DOUBLE,0); add_peratom("uMech",&uMech,DOUBLE,0); @@ -548,7 +567,26 @@ void Atom::peratom_create() add_peratom("edpd_cv",&edpd_cv,DOUBLE,0); add_peratom("edpd_temp",&edpd_temp,DOUBLE,0); add_peratom("edpd_flux",&edpd_flux,DOUBLE,0,1); // set per-thread flag - add_peratom("vest",&vest,DOUBLE,4); + add_peratom("cc",&cc,DOUBLE,1); + add_peratom("cc_flux",&cc_flux,DOUBLE,1,1); // set per-thread flag + + // USER-SPH package + + add_peratom("rho",&rho,DOUBLE,0); + add_peratom("drho",&drho,DOUBLE,0,1); // set per-thread flag + add_peratom("e",&e,DOUBLE,0); + add_peratom("de",&de,DOUBLE,0,1); // set per-thread flag + add_peratom("vest",&vest,DOUBLE,3); + add_peratom("cv",&cv,DOUBLE,0); + + // USER-SMD package + + add_peratom("contact_radius",&contact_radius,DOUBLE,0); + add_peratom("smd_data_9",&smd_data_9,DOUBLE,1); + add_peratom("smd_stress",&smd_stress,DOUBLE,1); + add_peratom("eff_plastic_strain",&eff_plastic_strain,DOUBLE,0); + add_peratom("eff_plastic_strain_rate",&eff_plastic_strain_rate,DOUBLE,0); + add_peratom("damage",&damage,DOUBLE,0); } /* ---------------------------------------------------------------------- @@ -579,6 +617,18 @@ void Atom::add_peratom(const char *name, void *address, nperatom++; } +/* ---------------------------------------------------------------------- + change the column count fof an existing peratom array entry + allows atom_style to specify column count as an argument + see atom_style tdpd as an example +------------------------------------------------------------------------- */ + +void Atom::add_peratom_change_columns(const char *name, int cols) +{ + for (int i = 0; i < nperatom; i++) + if (strcmp(name,peratom[i].name) == 0) peratom[i].cols = cols; +} + /* ---------------------------------------------------------------------- add info for a single per-atom array to PerAtom data struct cols = address of int variable with max columns per atom diff --git a/src/atom.h b/src/atom.h index a105b3e5b1..007d364a7b 100644 --- a/src/atom.h +++ b/src/atom.h @@ -60,6 +60,8 @@ class Atom : protected Pointers { imageint *image; double **x,**v,**f; + // charged and dipolar particles + double *rmass; double *q,**mu; @@ -69,7 +71,7 @@ class Atom : protected Pointers { double **omega,**angmom,**torque; int *ellipsoid,*line,*tri,*body; - // MOLECULE package + // molecular systems tagint *molecule; int *molindex,*molatom; @@ -101,15 +103,14 @@ class Atom : protected Pointers { // SPIN package - double **sp; - double **fm; - double **fm_long; + double **sp,**fm,**fm_long; - // USER-AWPMD and USER_EFF packages + // USER_EFF and USER-AWPMD packages int *spin; - double *eradius,*ervel,*erforce,*ervelforce; - double *cs,*csforce,*vforce; + double *eradius,*ervel,*erforce; + double *ervelforce,*cs,*csforce; + double **vforce; int *etag; // USER-DPD package @@ -261,6 +262,7 @@ class Atom : protected Pointers { void settings(class Atom *); void peratom_create(); void add_peratom(const char *, void *, int, int, int threadflag=0); + void add_peratom_change_columns(const char *, int); void add_peratom_vary(const char *, void *, int, int *, void *, int collength=0); void create_avec(const char *, int, char **, int); diff --git a/src/atom_vec_hybrid.h b/src/atom_vec_hybrid.h index 83d29112dd..7d838b7a7f 100644 --- a/src/atom_vec_hybrid.h +++ b/src/atom_vec_hybrid.h @@ -57,11 +57,6 @@ class AtomVecHybrid : public AtomVec { void pack_data_pre(int); void pack_data_post(int); - //void create_atom_post(int); - //void data_atom_post(int); - //void pack_data_pre(int); - //void pack_data_post(int); - int property_atom(char *); void pack_property_atom(int, double *, int, int); diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index 6796f9c8f2..81f1b02fdb 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -28,6 +28,7 @@ using namespace MathConst; AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) { + mass_type = 0; molecular = 0; atom->sphere_flag = 1; @@ -51,8 +52,6 @@ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) fields_create = (char *) "radius rmass omega"; fields_data_atom = (char *) "id type radius rmass x"; fields_data_vel = (char *) "id v omega"; - - setup_fields(); } /* ---------------------------------------------------------------------- @@ -74,6 +73,10 @@ void AtomVecSphere::process_args(int narg, char **arg) fields_comm = (char *) "radius rmass"; fields_comm_vel = (char *) "radius rmass omega"; + + // delay setting up of fields until now + + setup_fields(); } /* ---------------------------------------------------------------------- */ -- GitLab From f51ee40640c98b0b238638313598591d14078d64 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 3 Dec 2019 11:24:12 -0700 Subject: [PATCH 011/577] atom_vec.cpp --- src/atom_vec.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index cfbc8b12a6..bbfccadb89 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -133,7 +133,8 @@ void AtomVec::process_args(int narg, char ** /*arg*/) } /* ---------------------------------------------------------------------- - copy of velocity remap settings from Domain + pull settings from Domain needed for pack_comm_vel and pack_border_vel + child classes may override this method, but should also invoke it ------------------------------------------------------------------------- */ void AtomVec::init() -- GitLab From 9af08f2d5405dd781166f239c41ae1adb4eed34e Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Fri, 6 Dec 2019 10:06:16 -0700 Subject: [PATCH 012/577] small change for atom_style mdpd --- src/USER-MESO/atom_vec_mdpd.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/USER-MESO/atom_vec_mdpd.cpp b/src/USER-MESO/atom_vec_mdpd.cpp index eefda1ff6a..b87ff14c3c 100644 --- a/src/USER-MESO/atom_vec_mdpd.cpp +++ b/src/USER-MESO/atom_vec_mdpd.cpp @@ -55,6 +55,8 @@ AtomVecMDPD::AtomVecMDPD(LAMMPS *lmp) : AtomVec(lmp) void AtomVecMDPD::init() { + AtomVec::init(); + if (strcmp(update->unit_style,"lj") != 0) error->all(FLERR,"Atom style mdpd requires lj units"); } -- GitLab From db6d272303dfa748953c04f60b7041af00aa4ccb Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Fri, 13 Dec 2019 13:54:12 -0700 Subject: [PATCH 013/577] more additions to USER atom styles and bug fixes --- src/GRANULAR/fix_pour.cpp | 5 + src/MOLECULE/atom_vec_bond.cpp | 22 +- src/MOLECULE/atom_vec_bond.h | 4 + src/MOLECULE/atom_vec_full.cpp | 8 +- src/MOLECULE/atom_vec_molecular.cpp | 8 +- src/USER-AWPMD/atom_vec_wavepacket.cpp | 1122 +----------------------- src/USER-AWPMD/atom_vec_wavepacket.h | 75 +- src/USER-AWPMD/fix_nve_awpmd.cpp | 6 +- src/USER-DPD/atom_vec_dpd.cpp | 2 +- src/USER-EFF/atom_vec_electron.cpp | 3 - src/USER-EFF/pair_eff_cut.cpp | 27 +- src/USER-EFF/pair_eff_cut.h | 4 +- src/USER-MESO/atom_vec_edpd.cpp | 22 +- src/USER-MESO/atom_vec_tdpd.cpp | 2 +- src/USER-MESO/fix_mvv_edpd.cpp | 6 +- src/USER-SMD/atom_vec_smd.cpp | 4 +- src/atom.cpp | 4 + src/atom.h | 5 +- src/atom_vec.cpp | 24 +- src/atom_vec.h | 18 +- src/atom_vec_body.cpp | 45 +- src/atom_vec_body.h | 3 + src/atom_vec_ellipsoid.cpp | 4 +- src/atom_vec_line.cpp | 4 +- src/atom_vec_sphere.cpp | 20 +- src/atom_vec_tri.cpp | 6 +- src/fix_gravity.cpp | 21 +- src/replicate.cpp | 27 +- src/verlet.cpp | 2 +- 29 files changed, 216 insertions(+), 1287 deletions(-) diff --git a/src/GRANULAR/fix_pour.cpp b/src/GRANULAR/fix_pour.cpp index 2255f64eb2..b54920f7b2 100644 --- a/src/GRANULAR/fix_pour.cpp +++ b/src/GRANULAR/fix_pour.cpp @@ -40,6 +40,7 @@ using namespace MathConst; enum{ATOM,MOLECULE}; enum{ONE,RANGE,POLY}; +enum{CONSTANT,EQUAL}; // same as FixGravity #define EPSILON 0.001 #define SMALL 1.0e-10 @@ -318,6 +319,10 @@ void FixPour::init() if (ifix == -1) error->all(FLERR,"No fix gravity defined for fix pour"); + int varflag = ((FixGravity *) modify->fix[ifix])->varflag; + if (varflag != CONSTANT) + error->all(FLERR,"Fix gravity for fix pour must be constant"); + double xgrav = ((FixGravity *) modify->fix[ifix])->xgrav; double ygrav = ((FixGravity *) modify->fix[ifix])->ygrav; double zgrav = ((FixGravity *) modify->fix[ifix])->zgrav; diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp index 30ad7d83e1..00e8e3260d 100644 --- a/src/MOLECULE/atom_vec_bond.cpp +++ b/src/MOLECULE/atom_vec_bond.cpp @@ -60,6 +60,20 @@ AtomVecBond::~AtomVecBond() delete [] bond_negative; } +/* ---------------------------------------------------------------------- + grow atom arrays + must set local copy of body ptr + needed in replicate when 2 atom classes exist and pack_restart() is called +------------------------------------------------------------------------- */ + +void AtomVecBond::grow(int n) +{ + AtomVec::grow(n); + num_bond = atom->num_bond; + bond_type = atom->bond_type; +} + + /* ---------------------------------------------------------------------- modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ @@ -76,8 +90,8 @@ void AtomVecBond::pack_restart_pre(int ilocal) // flip any negative types to positive and flag which ones - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; + //int *num_bond = atom->num_bond; + //int **bond_type = atom->bond_type; any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { @@ -98,8 +112,8 @@ void AtomVecBond::pack_restart_post(int ilocal) // restore the flagged types to their negative values if (any_bond_negative) { - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; + //int *num_bond = atom->num_bond; + //int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[ilocal]; m++) if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } diff --git a/src/MOLECULE/atom_vec_bond.h b/src/MOLECULE/atom_vec_bond.h index c2bf7d6680..90c4b1f217 100644 --- a/src/MOLECULE/atom_vec_bond.h +++ b/src/MOLECULE/atom_vec_bond.h @@ -28,6 +28,7 @@ class AtomVecBond : public AtomVec { public: AtomVecBond(class LAMMPS *); ~AtomVecBond(); + void grow(int); void pack_restart_pre(int); void pack_restart_post(int); void unpack_restart_init(int); @@ -37,6 +38,9 @@ class AtomVecBond : public AtomVec { int any_bond_negative; int bond_per_atom; int *bond_negative; + + int *num_bond; + int **bond_type; }; } diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp index 9ab0a296e0..be7c92ce93 100644 --- a/src/MOLECULE/atom_vec_full.cpp +++ b/src/MOLECULE/atom_vec_full.cpp @@ -128,7 +128,7 @@ void AtomVecFull::pack_restart_pre(int ilocal) int *num_improper = atom->num_improper; int **improper_type = atom->improper_type; - int any_bond_negative = 0; + any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { if (bond_type[ilocal][m] < 0) { bond_negative[m] = 1; @@ -137,7 +137,7 @@ void AtomVecFull::pack_restart_pre(int ilocal) } else bond_negative[m] = 0; } - int any_angle_negative = 0; + any_angle_negative = 0; for (int m = 0; m < num_angle[ilocal]; m++) { if (angle_type[ilocal][m] < 0) { angle_negative[m] = 1; @@ -146,7 +146,7 @@ void AtomVecFull::pack_restart_pre(int ilocal) } else angle_negative[m] = 0; } - int any_dihedral_negative = 0; + any_dihedral_negative = 0; for (int m = 0; m < num_dihedral[ilocal]; m++) { if (dihedral_type[ilocal][m] < 0) { dihedral_negative[m] = 1; @@ -155,7 +155,7 @@ void AtomVecFull::pack_restart_pre(int ilocal) } else dihedral_negative[m] = 0; } - int any_improper_negative = 0; + any_improper_negative = 0; for (int m = 0; m < num_improper[ilocal]; m++) { if (improper_type[ilocal][m] < 0) { improper_negative[m] = 1; diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp index 52947ceb71..ea15216aee 100644 --- a/src/MOLECULE/atom_vec_molecular.cpp +++ b/src/MOLECULE/atom_vec_molecular.cpp @@ -128,7 +128,7 @@ void AtomVecMolecular::pack_restart_pre(int ilocal) int *num_improper = atom->num_improper; int **improper_type = atom->improper_type; - int any_bond_negative = 0; + any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { if (bond_type[ilocal][m] < 0) { bond_negative[m] = 1; @@ -137,7 +137,7 @@ void AtomVecMolecular::pack_restart_pre(int ilocal) } else bond_negative[m] = 0; } - int any_angle_negative = 0; + any_angle_negative = 0; for (int m = 0; m < num_angle[ilocal]; m++) { if (angle_type[ilocal][m] < 0) { angle_negative[m] = 1; @@ -146,7 +146,7 @@ void AtomVecMolecular::pack_restart_pre(int ilocal) } else angle_negative[m] = 0; } - int any_dihedral_negative = 0; + any_dihedral_negative = 0; for (int m = 0; m < num_dihedral[ilocal]; m++) { if (dihedral_type[ilocal][m] < 0) { dihedral_negative[m] = 1; @@ -155,7 +155,7 @@ void AtomVecMolecular::pack_restart_pre(int ilocal) } else dihedral_negative[m] = 0; } - int any_improper_negative = 0; + any_improper_negative = 0; for (int m = 0; m < num_improper[ilocal]; m++) { if (improper_type[ilocal][m] < 0) { improper_negative[m] = 1; diff --git a/src/USER-AWPMD/atom_vec_wavepacket.cpp b/src/USER-AWPMD/atom_vec_wavepacket.cpp index bce334a7b3..d643ae8e0a 100644 --- a/src/USER-AWPMD/atom_vec_wavepacket.cpp +++ b/src/USER-AWPMD/atom_vec_wavepacket.cpp @@ -18,13 +18,7 @@ #include "atom_vec_wavepacket.h" #include #include "atom.h" -#include "comm.h" -#include "domain.h" -#include "modify.h" -#include "fix.h" -#include "memory.h" #include "error.h" -#include "utils.h" using namespace LAMMPS_NS; @@ -32,1079 +26,69 @@ using namespace LAMMPS_NS; AtomVecWavepacket::AtomVecWavepacket(LAMMPS *lmp) : AtomVec(lmp) { - comm_x_only = comm_f_only = 0; - mass_type = 1; molecular = 0; forceclearflag = 1; - size_forward = 4; // coords[3]+radius[1] - size_reverse = 10; // force[3]+erforce[1]+ervelforce[1]+vforce[3]+csforce[2] - size_border = 10; // coords[3]+tag[1]+type[1]+mask[1]+q[1]+spin[1]+eradius[1]+etag[1] - size_velocity = 6; // +velocities[3]+ ervel[1]+cs[2] - size_data_atom = 11; // for input file: 1-tag 2-type 3-q 4-spin 5-eradius 6-etag 7-cs_re 8-cs_im 9-x 10-y 11-z - size_data_vel = 5; // for input file: vx vy vz ervel - xcol_data = 9; // starting column for x data - atom->wavepacket_flag = 1; - atom->electron_flag = 1; // compatible with eff + + atom->electron_flag = 1; // compatible with eff atom->q_flag = atom->spin_flag = atom->eradius_flag = atom->ervel_flag = atom->erforce_flag = 1; + atom->cs_flag = atom->csforce_flag = + atom->vforce_flag = atom->ervelforce_flag = atom->etag_flag = 1; - atom->cs_flag = atom->csforce_flag = atom->vforce_flag = atom->ervelforce_flag = atom->etag_flag = 1; -} - -/* ---------------------------------------------------------------------- - grow atom-electron arrays - n = 0 grows arrays by a chunk - n > 0 allocates arrays to size n -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::grow(int n) -{ - if (n == 0) grow_nmax(); - else nmax = n; - atom->nmax = nmax; - - tag = memory->grow(atom->tag,nmax,"atom:tag"); - type = memory->grow(atom->type,nmax,"atom:type"); - mask = memory->grow(atom->mask,nmax,"atom:mask"); - image = memory->grow(atom->image,nmax,"atom:image"); - x = memory->grow(atom->x,nmax,3,"atom:x"); - v = memory->grow(atom->v,nmax,3,"atom:v"); - f = memory->grow(atom->f,nmax*comm->nthreads,3,"atom:f"); - - q = memory->grow(atom->q,nmax,"atom:q"); - spin = memory->grow(atom->spin,nmax,"atom:spin"); - eradius = memory->grow(atom->eradius,nmax,"atom:eradius"); - ervel = memory->grow(atom->ervel,nmax,"atom:ervel"); - erforce = memory->grow(atom->erforce,nmax*comm->nthreads,"atom:erforce"); + // 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 - cs = memory->grow(atom->cs,2*nmax,"atom:cs"); - csforce = memory->grow(atom->csforce,2*nmax,"atom:csforce"); - vforce = memory->grow(atom->vforce,3*nmax,"atom:vforce"); - ervelforce = memory->grow(atom->ervelforce,nmax,"atom:ervelforce"); - etag = memory->grow(atom->etag,nmax,"atom:etag"); + fields_grow = (char *) + "q spin eradius ervel erforce cs csforce " + "vforce ervelforce etag"; + fields_copy = (char *) "q spin eradius ervel cs etag"; + fields_comm = (char *) "eradius"; + fields_comm_vel = (char *) "eradius ervel cs"; + fields_reverse = (char *) "erforce ervelforce vforce csforce"; + fields_border = (char *) "q spin eradius etag"; + fields_border_vel = (char *) "q spin eradius etag ervel cs"; + fields_exchange = (char *) "q spin eradius ervel etag cs"; + fields_restart = (char *) "q spin eradius ervel etag cs"; + fields_create = (char *) "q spin eradius ervel etag cs"; + fields_data_atom = (char *) "id type q spin eradius etag cs x"; + fields_data_vel = (char *) "id v ervel"; - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); + setup_fields(); } /* ---------------------------------------------------------------------- - reset local array ptrs + clear extra forces starting at atom N + nbytes = # of bytes to clear for a per-atom vector ------------------------------------------------------------------------- */ -void AtomVecWavepacket::grow_reset() -{ - tag = atom->tag; type = atom->type; - mask = atom->mask; image = atom->image; - x = atom->x; v = atom->v; f = atom->f; - q = atom->q; - eradius = atom->eradius; ervel = atom->ervel; erforce = atom->erforce; - - cs = atom->cs; - csforce = atom->csforce; - vforce = atom->vforce; - ervelforce = atom->ervelforce; - etag = atom->etag; -} - -/* ---------------------------------------------------------------------- - copy atom I info to atom J -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::copy(int i, int j, int delflag) -{ - tag[j] = tag[i]; - type[j] = type[i]; - mask[j] = mask[i]; - image[j] = image[i]; - x[j][0] = x[i][0]; - x[j][1] = x[i][1]; - x[j][2] = x[i][2]; - v[j][0] = v[i][0]; - v[j][1] = v[i][1]; - v[j][2] = v[i][2]; - - q[j] = q[i]; - spin[j] = spin[i]; - eradius[j] = eradius[i]; - ervel[j] = ervel[i]; - - cs[2*j] = cs[2*i]; - cs[2*j+1] = cs[2*i+1]; - etag[j] = etag[i]; - - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - modify->fix[atom->extra_grow[iextra]]->copy_arrays(i,j,delflag); -} - -/* ---------------------------------------------------------------------- */ - void AtomVecWavepacket::force_clear(int n, size_t nbytes) { - memset(&erforce[n],0,nbytes); -} - -/* ---------------------------------------------------------------------- */ -// this will be used as partial pack for unsplit Hartree packets (v, ervel not regarded as separate variables) - -int AtomVecWavepacket::pack_comm(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = eradius[j]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = eradius[j]; - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ -// this is a complete pack of all 'position' variables of AWPMD - -int AtomVecWavepacket::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = eradius[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]*domain->xprd + pbc[5]*domain->xy + pbc[4]*domain->xz; - dy = pbc[1]*domain->yprd + pbc[3]*domain->yz; - dz = pbc[2]*domain->zprd; - } - if (!deform_vremap) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = eradius[j]; - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = eradius[j]; - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - } - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_comm_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = eradius[j]; - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecWavepacket::unpack_comm(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - eradius[i] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecWavepacket::unpack_comm_vel(int n, int first, double *buf) -{ - int i,m,last; - - 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++]; - eradius[i] = buf[m++]; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - - ervel[i] = buf[m++]; - cs[2*i] = buf[m++]; - cs[2*i+1] = buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::unpack_comm_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++){ - eradius[i] = buf[m++]; - ervel[i] = buf[m++]; - cs[2*i] = buf[m++]; - cs[2*i+1] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_reverse(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { //10 - buf[m++] = f[i][0]; - buf[m++] = f[i][1]; - buf[m++] = f[i][2]; - buf[m++] = erforce[i]; - - buf[m++] = ervelforce[i]; - buf[m++] = vforce[3*i]; - buf[m++] = vforce[3*i+1]; - buf[m++] = vforce[3*i+2]; - buf[m++] = csforce[2*i]; - buf[m++] = csforce[2*i+1]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_reverse_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++){ - buf[m++] = erforce[i]; - - buf[m++] = ervelforce[i]; - buf[m++] = vforce[3*i]; - buf[m++] = vforce[3*i+1]; - buf[m++] = vforce[3*i+2]; - buf[m++] = csforce[2*i]; - buf[m++] = csforce[2*i+1]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecWavepacket::unpack_reverse(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - f[j][0] += buf[m++]; - f[j][1] += buf[m++]; - f[j][2] += buf[m++]; - erforce[j] += buf[m++]; - - ervelforce[j] += buf[m++]; - vforce[3*j] += buf[m++]; - vforce[3*j+1] += buf[m++]; - vforce[3*j+2] += buf[m++]; - csforce[2*j] += buf[m++]; - csforce[2*j+1] += buf[m++]; - } -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::unpack_reverse_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - erforce[j] += buf[m++]; - - ervelforce[j] += buf[m++]; - vforce[3*j] += buf[m++]; - vforce[3*j+1] += buf[m++]; - vforce[3*j+2] += buf[m++]; - csforce[2*j] += buf[m++]; - csforce[2*j+1] += buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ -// will be used for Hartree unsplit version (the etag is added however) -int AtomVecWavepacket::pack_border(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = ubuf(etag[j]).d; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = ubuf(etag[j]).d; - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_border_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) -{ - int i,j,m; - double dx,dy,dz,dvx,dvy,dvz; - - m = 0; - if (pbc_flag == 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]; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = ubuf(etag[j]).d; - - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - } else { - if (domain->triclinic == 0) { - dx = pbc[0]*domain->xprd; - dy = pbc[1]*domain->yprd; - dz = pbc[2]*domain->zprd; - } else { - dx = pbc[0]; - dy = pbc[1]; - dz = pbc[2]; - } - if (domain->triclinic == 0) { - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = ubuf(etag[j]).d; - - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - - - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - } else { - dvx = pbc[0]*h_rate[0] + pbc[5]*h_rate[5] + pbc[4]*h_rate[4]; - dvy = pbc[1]*h_rate[1] + pbc[3]*h_rate[3]; - dvz = pbc[2]*h_rate[2]; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = x[j][0] + dx; - buf[m++] = x[j][1] + dy; - buf[m++] = x[j][2] + dz; - buf[m++] = ubuf(tag[j]).d; - buf[m++] = ubuf(type[j]).d; - buf[m++] = ubuf(mask[j]).d; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - buf[m++] = ubuf(etag[j]).d; - - if (mask[i] & deform_groupbit) { - buf[m++] = v[j][0] + dvx; - buf[m++] = v[j][1] + dvy; - buf[m++] = v[j][2] + dvz; - } else { - buf[m++] = v[j][0]; - buf[m++] = v[j][1]; - buf[m++] = v[j][2]; - } - - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - } - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]->pack_border(n,list,&buf[m]); - - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_border_hybrid(int n, int *list, double *buf) -{ - int i,j,m; - - m = 0; - for (i = 0; i < n; i++) { - j = list[i]; - buf[m++] = q[j]; - buf[m++] = ubuf(spin[j]).d; - buf[m++] = eradius[j]; - - buf[m++] = ubuf(etag[j]).d; - buf[m++] = ervel[j]; - buf[m++] = cs[2*j]; - buf[m++] = cs[2*j+1]; - } - return m; -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecWavepacket::unpack_border(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - spin[i] = (int) ubuf(buf[m++]).i; - eradius[i] = buf[m++]; - etag[i] = (int) ubuf(buf[m++]).i; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -void AtomVecWavepacket::unpack_border_vel(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - if (i == nmax) grow(0); - x[i][0] = buf[m++]; - x[i][1] = buf[m++]; - x[i][2] = buf[m++]; - tag[i] = (tagint) ubuf(buf[m++]).i; - type[i] = (int) ubuf(buf[m++]).i; - mask[i] = (int) ubuf(buf[m++]).i; - q[i] = buf[m++]; - spin[i] = (int) ubuf(buf[m++]).i; - eradius[i] = buf[m++]; - etag[i] = (int) ubuf(buf[m++]).i; - v[i][0] = buf[m++]; - v[i][1] = buf[m++]; - v[i][2] = buf[m++]; - ervel[i] = buf[m++]; - cs[2*i] = buf[m++]; - cs[2*i+1] = buf[m++]; - } - - if (atom->nextra_border) - for (int iextra = 0; iextra < atom->nextra_border; iextra++) - m += modify->fix[atom->extra_border[iextra]]-> - unpack_border(n,first,&buf[m]); -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::unpack_border_hybrid(int n, int first, double *buf) -{ - int i,m,last; - - m = 0; - last = first + n; - for (i = first; i < last; i++) { - q[i] = buf[m++]; - spin[i] = (int) ubuf(buf[m++]).i; - eradius[i] = buf[m++]; - etag[i] = (int) ubuf(buf[m++]).i; - ervel[i] = buf[m++]; - cs[2*i] = buf[m++]; - cs[2*i+1] = buf[m++]; - } - return m; -} - -/* ---------------------------------------------------------------------- - pack data for atom I for sending to another proc - xyz must be 1st 3 values, so comm::exchange() can test on them -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_exchange(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - - buf[m++] = q[i]; - buf[m++] = ubuf(spin[i]).d; - buf[m++] = eradius[i]; - buf[m++] = ervel[i]; - - buf[m++] = ubuf(etag[i]).d; - buf[m++] = cs[2*i]; - buf[m++] = cs[2*i+1]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]->pack_exchange(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- */ - -int AtomVecWavepacket::unpack_exchange(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - - q[nlocal] = buf[m++]; - spin[nlocal] = (int) ubuf(buf[m++]).i; - eradius[nlocal] = buf[m++]; - ervel[nlocal] = buf[m++]; - - etag[nlocal] = (int) ubuf(buf[m++]).i; - cs[2*nlocal] = buf[m++]; - cs[2*nlocal+1] = buf[m++]; - - if (atom->nextra_grow) - for (int iextra = 0; iextra < atom->nextra_grow; iextra++) - m += modify->fix[atom->extra_grow[iextra]]-> - unpack_exchange(nlocal,&buf[m]); - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - size of restart data for all atoms owned by this proc - include extra data stored by fixes -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::size_restart() -{ - int i; - - int nlocal = atom->nlocal; - int n = 18 * nlocal; // Associated with pack_restart - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - for (i = 0; i < nlocal; i++) - n += modify->fix[atom->extra_restart[iextra]]->size_restart(i); - - return n; -} - -/* ---------------------------------------------------------------------- - pack atom I's data for restart file including extra quantities - xyz must be 1st 3 values, so that read_restart can test on them - molecular types may be negative, but write as positive -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_restart(int i, double *buf) -{ - int m = 1; - buf[m++] = x[i][0]; - buf[m++] = x[i][1]; - buf[m++] = x[i][2]; - buf[m++] = ubuf(tag[i]).d; - buf[m++] = ubuf(type[i]).d; - buf[m++] = ubuf(mask[i]).d; - buf[m++] = ubuf(image[i]).d; - buf[m++] = v[i][0]; - buf[m++] = v[i][1]; - buf[m++] = v[i][2]; - - buf[m++] = q[i]; - buf[m++] = ubuf(spin[i]).d; - buf[m++] = eradius[i]; - buf[m++] = ervel[i]; - - buf[m++] = ubuf(etag[i]).d; - buf[m++] = cs[2*i]; - buf[m++] = cs[2*i+1]; - - if (atom->nextra_restart) - for (int iextra = 0; iextra < atom->nextra_restart; iextra++) - m += modify->fix[atom->extra_restart[iextra]]->pack_restart(i,&buf[m]); - - buf[0] = m; - return m; -} - -/* ---------------------------------------------------------------------- - unpack data for one atom from restart file including extra quantities -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::unpack_restart(double *buf) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) { - grow(0); - if (atom->nextra_store) - memory->grow(atom->extra,nmax,atom->nextra_store,"atom:extra"); - } - - int m = 1; - x[nlocal][0] = buf[m++]; - x[nlocal][1] = buf[m++]; - x[nlocal][2] = buf[m++]; - tag[nlocal] = (tagint) ubuf(buf[m++]).i; - type[nlocal] = (int) ubuf(buf[m++]).i; - mask[nlocal] = (int) ubuf(buf[m++]).i; - image[nlocal] = (imageint) ubuf(buf[m++]).i; - v[nlocal][0] = buf[m++]; - v[nlocal][1] = buf[m++]; - v[nlocal][2] = buf[m++]; - - q[nlocal] = buf[m++]; - spin[nlocal] = (int) ubuf(buf[m++]).i; - eradius[nlocal] = buf[m++]; - ervel[nlocal] = buf[m++]; - - etag[nlocal] = (int) ubuf(buf[m++]).i; - cs[2*nlocal] = buf[m++]; - cs[2*nlocal+1] = buf[m++]; - - double **extra = atom->extra; - if (atom->nextra_store) { - int size = static_cast (buf[0]) - m; - for (int i = 0; i < size; i++) extra[nlocal][i] = buf[m++]; - } - - atom->nlocal++; - return m; -} - -/* ---------------------------------------------------------------------- - create one atom of itype at coord - set other values to defaults - AWPMD: creates a proton -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::create_atom(int itype, double *coord) -{ - int nlocal = atom->nlocal; - if (nlocal == nmax) grow(0); - - tag[nlocal] = 0; - type[nlocal] = itype; - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - mask[nlocal] = 1; - image[nlocal] = ((imageint) IMGMAX << IMG2BITS) | - ((imageint) IMGMAX << IMGBITS) | IMGMAX; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - - q[nlocal] = 1.; - spin[nlocal] = 0; - eradius[nlocal] = 0.0; - ervel[nlocal] = 0.0; - - etag[nlocal] = 0; - cs[2*nlocal] = 0.; - cs[2*nlocal+1] = 0.; - - atom->nlocal++; -} - -/* ---------------------------------------------------------------------- - unpack one line from Atoms section of data file - initialize other atom quantities - AWPMD: 0-tag 1-type 2-q 3-spin 4-eradius 5-etag 6-cs_re 7-cs_im -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::data_atom(double *coord, imageint imagetmp, - char **values) -{ - int nlocal = atom->nlocal; - - if (nlocal == nmax) grow(0); - - tag[nlocal] = utils::tnumeric(FLERR,values[0],true,lmp); - type[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) - error->one(FLERR,"Invalid atom type in Atoms section of data file"); - - q[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - spin[nlocal] = utils::inumeric(FLERR,values[3],true,lmp); - eradius[nlocal] = utils::numeric(FLERR,values[4],true,lmp); - if (eradius[nlocal] < 0.0) - error->one(FLERR,"Invalid eradius in Atoms section of data file"); - - etag[nlocal] = utils::inumeric(FLERR,values[5],true,lmp); - cs[2*nlocal] = utils::numeric(FLERR,values[6],true,lmp); - cs[2*nlocal+1] = utils::numeric(FLERR,values[7],true,lmp); - - x[nlocal][0] = coord[0]; - x[nlocal][1] = coord[1]; - x[nlocal][2] = coord[2]; - - image[nlocal] = imagetmp; - - mask[nlocal] = 1; - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - ervel[nlocal] = 0.0; - - atom->nlocal++; + memset(&atom->erforce[n],0,nbytes); } /* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Atoms section of data file - initialize other atom quantities for this sub-style + initialize non-zero atom quantities + make each atom a proton ------------------------------------------------------------------------- */ -int AtomVecWavepacket::data_atom_hybrid(int nlocal, char **values) +void AtomVecWavepacket::create_atom_post(int ilocal) { - q[nlocal] = utils::numeric(FLERR,values[0],true,lmp); - spin[nlocal] = utils::inumeric(FLERR,values[1],true,lmp); - eradius[nlocal] = utils::numeric(FLERR,values[2],true,lmp); - if (eradius[nlocal] < 0.0) - error->one(FLERR,"Invalid eradius in Atoms section of data file"); - - etag[nlocal] = utils::inumeric(FLERR,values[3],true,lmp); - cs[2*nlocal] = utils::inumeric(FLERR,values[4],true,lmp); - cs[2*nlocal+1] = utils::numeric(FLERR,values[5],true,lmp); - - v[nlocal][0] = 0.0; - v[nlocal][1] = 0.0; - v[nlocal][2] = 0.0; - ervel[nlocal] = 0.0; - - return 3; + atom->q[ilocal] = 1.0; } /* ---------------------------------------------------------------------- - unpack one line from Velocities section of data file + modify what AtomVec::data_atom() just unpacked + or initialize other atom quantities ------------------------------------------------------------------------- */ -void AtomVecWavepacket::data_vel(int m, char **values) +void AtomVecWavepacket::data_atom_post(int ilocal) { - v[m][0] = utils::numeric(FLERR,values[0],true,lmp); - v[m][1] = utils::numeric(FLERR,values[1],true,lmp); - v[m][2] = utils::numeric(FLERR,values[2],true,lmp); - ervel[m] = utils::numeric(FLERR,values[3],true,lmp); -} - -/* ---------------------------------------------------------------------- - unpack hybrid quantities from one line in Velocities section of data file -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::data_vel_hybrid(int m, char **values) -{ - ervel[m] = utils::numeric(FLERR,values[0],true,lmp); - return 1; -} - -/* ---------------------------------------------------------------------- - pack atom info for data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::pack_data(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = ubuf(type[i]).d; - buf[i][2] = q[i]; - buf[i][3] = ubuf(spin[i]).d; - buf[i][4] = eradius[i]; - buf[i][5] = ubuf(etag[i]).d; - buf[i][6] = cs[2*i]; - buf[i][7] = cs[2*i+1]; - buf[i][8] = x[i][0]; - buf[i][9] = x[i][1]; - buf[i][10] = x[i][2]; - buf[i][11] = ubuf((image[i] & IMGMASK) - IMGMAX).d; - buf[i][12] = ubuf((image[i] >> IMGBITS & IMGMASK) - IMGMAX).d; - buf[i][13] = ubuf((image[i] >> IMG2BITS) - IMGMAX).d; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid atom info for data file -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_data_hybrid(int i, double *buf) -{ - buf[0] = q[i]; - buf[1] = ubuf(spin[i]).d; - buf[2] = eradius[i]; - buf[3] = ubuf(etag[i]).d; - buf[4] = cs[2*i]; - buf[5] = cs[2*i+1]; - return 6; -} - -/* ---------------------------------------------------------------------- - write atom info to data file including 3 image flags -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::write_data(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT - " %d %-1.16e %d %-1.16e %d %-1.16e %-1.16e %-1.16e " - "%-1.16e %-1.16e %d %d %d\n", - (tagint) ubuf(buf[i][0]).i,(int) ubuf(buf[i][1]).i, - buf[i][2],(int) ubuf(buf[i][3]).i,buf[i][4], - (int) ubuf(buf[i][5]).i,buf[i][6],buf[i][8], - buf[i][8],buf[i][9],buf[i][10], - (int) ubuf(buf[i][11]).i,(int) ubuf(buf[i][12]).i, - (int) ubuf(buf[i][13]).i); -} - -/* ---------------------------------------------------------------------- - write hybrid atom info to data file -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::write_data_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e %d %-1.16e %d %-1.16e %-1.16e", - buf[0],(int) ubuf(buf[1]).i,buf[2],(int) ubuf(buf[3]).i, - buf[4],buf[5]); - return 6; -} - -/* ---------------------------------------------------------------------- - pack velocity info for data file -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::pack_vel(double **buf) -{ - int nlocal = atom->nlocal; - for (int i = 0; i < nlocal; i++) { - buf[i][0] = ubuf(tag[i]).d; - buf[i][1] = v[i][0]; - buf[i][2] = v[i][1]; - buf[i][3] = v[i][2]; - buf[i][4] = ervel[i]; - } -} - -/* ---------------------------------------------------------------------- - pack hybrid velocity info for data file -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::pack_vel_hybrid(int i, double *buf) -{ - buf[0] = ervel[i]; - return 1; -} - -/* ---------------------------------------------------------------------- - write velocity info to data file -------------------------------------------------------------------------- */ - -void AtomVecWavepacket::write_vel(FILE *fp, int n, double **buf) -{ - for (int i = 0; i < n; i++) - fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3],buf[i][4]); -} - -/* ---------------------------------------------------------------------- - write hybrid velocity info to data file -------------------------------------------------------------------------- */ - -int AtomVecWavepacket::write_vel_hybrid(FILE *fp, double *buf) -{ - fprintf(fp," %-1.16e",buf[0]); - return 1; + atom->ervel[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -1131,27 +115,31 @@ void AtomVecWavepacket::pack_property_atom(int index, double *buf, { int *mask = atom->mask; int nlocal = atom->nlocal; - int n = 0; + int n = 0; if (index == 0) { + int *spin = atom->spin; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = spin[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 1) { + double *eradius = atom->eradius; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = eradius[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 2) { + double *ervel = atom->ervel; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = ervel[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 3) { + double *erforce = atom->erforce; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = erforce[i]; else buf[n] = 0.0; @@ -1159,35 +147,3 @@ void AtomVecWavepacket::pack_property_atom(int index, double *buf, } } } - -/* ---------------------------------------------------------------------- - return # of bytes of allocated memory -------------------------------------------------------------------------- */ - -bigint AtomVecWavepacket::memory_usage() -{ - bigint bytes = 0; - - if (atom->memcheck("tag")) bytes += memory->usage(tag,nmax); - if (atom->memcheck("type")) bytes += memory->usage(type,nmax); - if (atom->memcheck("mask")) bytes += memory->usage(mask,nmax); - if (atom->memcheck("image")) bytes += memory->usage(image,nmax); - if (atom->memcheck("x")) bytes += memory->usage(x,nmax,3); - if (atom->memcheck("v")) bytes += memory->usage(v,nmax,3); - if (atom->memcheck("f")) bytes += memory->usage(f,nmax*comm->nthreads,3); - - if (atom->memcheck("q")) bytes += memory->usage(q,nmax); - if (atom->memcheck("spin")) bytes += memory->usage(spin,nmax); - if (atom->memcheck("eradius")) bytes += memory->usage(eradius,nmax); - if (atom->memcheck("ervel")) bytes += memory->usage(ervel,nmax); - if (atom->memcheck("erforce")) - bytes += memory->usage(erforce,nmax*comm->nthreads); - - if (atom->memcheck("ervelforce")) bytes += memory->usage(ervelforce,nmax); - if (atom->memcheck("cs")) bytes += memory->usage(cs,2*nmax); - if (atom->memcheck("csforce")) bytes += memory->usage(csforce,2*nmax); - if (atom->memcheck("vforce")) bytes += memory->usage(vforce,3*nmax); - if (atom->memcheck("etag")) bytes += memory->usage(etag,nmax); - - return bytes; -} diff --git a/src/USER-AWPMD/atom_vec_wavepacket.h b/src/USER-AWPMD/atom_vec_wavepacket.h index d1a0c7c7f2..e7db15db14 100644 --- a/src/USER-AWPMD/atom_vec_wavepacket.h +++ b/src/USER-AWPMD/atom_vec_wavepacket.h @@ -11,11 +11,6 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ -/* ---------------------------------------------------------------------- - Contributing author: Ilya Valuev (JIHT RAS) -------------------------------------------------------------------------- */ - - #ifdef ATOM_CLASS AtomStyle(wavepacket,AtomVecWavepacket) @@ -32,77 +27,11 @@ namespace LAMMPS_NS { class AtomVecWavepacket : public AtomVec { public: AtomVecWavepacket(class LAMMPS *); - ~AtomVecWavepacket() {} - void grow(int); - void grow_reset(); - void copy(int, int, int); void force_clear(int, size_t); - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - int pack_comm_hybrid(int, int *, double *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); - int unpack_comm_hybrid(int, int, double *); - int pack_reverse(int, int, double *); - int pack_reverse_hybrid(int, int, double *); - void unpack_reverse(int, int *, double *); - int unpack_reverse_hybrid(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - int pack_border_hybrid(int, int *, double *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); - int unpack_border_hybrid(int, int, double *); - int pack_exchange(int, double *); - int unpack_exchange(double *); - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); - void create_atom(int, double *); - void data_atom(double *, imageint, char **); - int data_atom_hybrid(int, char **); - void data_vel(int, char **); - int data_vel_hybrid(int, char **); - void pack_data(double **); - int pack_data_hybrid(int, double *); - void write_data(FILE *, int, double **); - int write_data_hybrid(FILE *, double *); - void pack_vel(double **); - int pack_vel_hybrid(int, double *); - void write_vel(FILE *, int, double **); - int write_vel_hybrid(FILE *, double *); + void create_atom_post(int); + void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); - bigint memory_usage(); - -private: - tagint *tag; - int *type,*mask; - imageint *image; - double **x,**v,**f; - - ///\en spin: -1 or 1 for electron, 0 for ion (compatible with eff) - int *spin; - ///\en charge: must be specified in the corresponding units (-1 for electron in real units, eff compatible) - double *q; - ///\en width of the wavepacket (compatible with eff) - double *eradius; - ///\en width velocity for the wavepacket (compatible with eff) - double *ervel; - ///\en (generalized) force on width (compatible with eff) - double *erforce; - - // AWPMD- specific: - ///\en electron tag: must be the same for the WPs belonging to the same electron - int *etag; - ///\en wavepacket split coefficients: cre, cim, size is 2*N - double *cs; - ///\en force on wavepacket split coefficients: re, im, size is 2*N - double *csforce; - ///\en (generalized) force on velocity, size is 3*N - double *vforce; - ///\en (generalized) force on radius velocity, size is N - double *ervelforce; }; } diff --git a/src/USER-AWPMD/fix_nve_awpmd.cpp b/src/USER-AWPMD/fix_nve_awpmd.cpp index b4a1cbf72a..2aa2e7680b 100644 --- a/src/USER-AWPMD/fix_nve_awpmd.cpp +++ b/src/USER-AWPMD/fix_nve_awpmd.cpp @@ -74,8 +74,6 @@ void FixNVEAwpmd::init() void FixNVEAwpmd::initial_integrate(int /* vflag */) { - - // update v,vr and x,radius of atoms in group double **x = atom->x; @@ -84,7 +82,7 @@ void FixNVEAwpmd::initial_integrate(int /* vflag */) double *ervel = atom->ervel; double **f = atom->f; double *erforce = atom->erforce; - double *vforce=atom->vforce; + double **vforce=atom->vforce; double *ervelforce=atom->ervelforce; double *mass = atom->mass; @@ -101,7 +99,7 @@ void FixNVEAwpmd::initial_integrate(int /* vflag */) double dtfm = dtf / mass[type[i]]; double dtfmr=dtfm; for(int j=0;j<3;j++){ - x[i][j] += dtv*vforce[3*i+j]; + x[i][j] += dtv*vforce[i][j]; v[i][j] += dtfm*f[i][j]; } eradius[i]+= dtv*ervelforce[i]; diff --git a/src/USER-DPD/atom_vec_dpd.cpp b/src/USER-DPD/atom_vec_dpd.cpp index ce35178d8d..124a081191 100644 --- a/src/USER-DPD/atom_vec_dpd.cpp +++ b/src/USER-DPD/atom_vec_dpd.cpp @@ -47,7 +47,7 @@ AtomVecDPD::AtomVecDPD(LAMMPS *lmp) : AtomVec(lmp) fields_restart = (char *) "dpdTheta uCond uMech uChem"; fields_create = (char *) "rho dpdTheta uCond uMech uChem uCG uCGnew duChem"; fields_data_atom = (char *) "id type dpdTheta x"; - fields_data_vel = (char *) "id v omega"; + fields_data_vel = (char *) "id v"; setup_fields(); } diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp index 3688f7f582..0ac56c48a3 100644 --- a/src/USER-EFF/atom_vec_electron.cpp +++ b/src/USER-EFF/atom_vec_electron.cpp @@ -44,8 +44,6 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) molecular = 0; forceclearflag = 1; - atom->ecp_flag = 0; - atom->electron_flag = 1; atom->q_flag = atom->spin_flag = atom->eradius_flag = atom->ervel_flag = atom->erforce_flag = 1; @@ -99,7 +97,6 @@ void AtomVecElectron::create_atom_post(int ilocal) void AtomVecElectron::data_atom_post(int ilocal) { atom->ervel[ilocal] = 0.0; - if (atom->spin[ilocal] == 3) atom->ecp_flag = 1; } /* ---------------------------------------------------------------------- diff --git a/src/USER-EFF/pair_eff_cut.cpp b/src/USER-EFF/pair_eff_cut.cpp index e7aed14030..f9333f4bec 100644 --- a/src/USER-EFF/pair_eff_cut.cpp +++ b/src/USER-EFF/pair_eff_cut.cpp @@ -801,7 +801,7 @@ void PairEffCut::settings(int narg, char **arg) int atype; int iarg = 1; - int ecp_found = 0; + ecp_found = 0; while (iarg < narg) { if (strcmp(arg[iarg],"limit/eradius") == 0) { @@ -821,17 +821,15 @@ void PairEffCut::settings(int narg, char **arg) else if (strcmp(arg[iarg+1],"O") == 0) ecp_type[atype] = 8; else if (strcmp(arg[iarg+1],"Al") == 0) ecp_type[atype] = 13; else if (strcmp(arg[iarg+1],"Si") == 0) ecp_type[atype] = 14; - else error->all(FLERR, "Note: there are no default parameters for this atom ECP\n"); + else error->all(FLERR, "No default parameters for this atom ECP\n"); iarg += 2; ecp_found = 1; } - } + } else error->all(FLERR,"Illegal pair style command"); } - if (!ecp_found && atom->ecp_flag) - error->all(FLERR,"Need to specify ECP type on pair_style command"); - // Need to introduce 2 new constants w/out changing update.cpp + if (force->qqr2e==332.06371) { // i.e. Real units chosen h2e = 627.509; // hartree->kcal/mol hhmss2e = 175.72044219620075; // hartree->kcal/mol * (Bohr->Angstrom)^2 @@ -872,9 +870,24 @@ void PairEffCut::init_style() if (update->whichflag == 1) { if (force->qqr2e == 332.06371 && update->dt == 1.0) - error->all(FLERR,"You must lower the default real units timestep for pEFF "); + error->all(FLERR,"Must lower the default real units timestep for pEFF "); } + // check if any atom's spin = 3 and ECP type was not set + + int *spin = atom->spin; + int nlocal = atom->nlocal; + + int flag = 0; + for (int i = 0; i < nlocal; i++) + if (spin[i] == 3) flag = 1; + + int flagall; + MPI_Allreduce(&flag,&flagall,1,MPI_INT,MPI_SUM,world); + + if (flagall && !ecp_found) + error->all(FLERR,"Need to specify ECP type on pair_style command"); + // need a half neigh list and optionally a granular history neigh list neighbor->request(this,instance_me); diff --git a/src/USER-EFF/pair_eff_cut.h b/src/USER-EFF/pair_eff_cut.h index 63dabe5db8..bd04344373 100644 --- a/src/USER-EFF/pair_eff_cut.h +++ b/src/USER-EFF/pair_eff_cut.h @@ -46,10 +46,12 @@ class PairEffCut : public Pair { private: int limit_eradius_flag, pressure_with_evirials_flag; + int ecp_found; double cut_global; double **cut; int ecp_type[100]; - double PAULI_CORE_A[100], PAULI_CORE_B[100], PAULI_CORE_C[100], PAULI_CORE_D[100], PAULI_CORE_E[100]; + double PAULI_CORE_A[100],PAULI_CORE_B[100],PAULI_CORE_C[100]; + double PAULI_CORE_D[100],PAULI_CORE_E[100]; double hhmss2e, h2e; int nmax; diff --git a/src/USER-MESO/atom_vec_edpd.cpp b/src/USER-MESO/atom_vec_edpd.cpp index 7a031c256b..e06ac633ec 100644 --- a/src/USER-MESO/atom_vec_edpd.cpp +++ b/src/USER-MESO/atom_vec_edpd.cpp @@ -41,16 +41,16 @@ AtomVecEDPD::AtomVecEDPD(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 = (char *) "edpd_cv edpd_temp edpd_flux vest"; - fields_copy = (char *) "edpd_cv edpd_temp edpd_flux vest"; - fields_comm = (char *) "edpd_temp vest"; - fields_comm_vel = (char *) "edpd_temp vest"; + fields_grow = (char *) "edpd_cv edpd_temp edpd_flux vest vest_temp"; + fields_copy = (char *) "edpd_cv edpd_temp edpd_flux vest vest_temp"; + fields_comm = (char *) "edpd_temp vest vest_temp"; + fields_comm_vel = (char *) "edpd_temp vest vest_temp"; fields_reverse = (char *) "edpd_flux"; - fields_border = (char *) "edpd_cv edpd_temp vest"; - fields_border_vel = (char *) "edpd_cv edpd_temp vest"; - fields_exchange = (char *) "edpd_cv edpd_temp vest"; - fields_restart = (char * ) "edpd_cv edpd_temp vest"; - fields_create = (char *) "edpd_cv edpd_temp edpd_flux vest"; + fields_border = (char *) "edpd_cv edpd_temp vest vest_temp"; + fields_border_vel = (char *) "edpd_cv edpd_temp vest vest_temp"; + fields_exchange = (char *) "edpd_cv edpd_temp vest vest_temp"; + fields_restart = (char * ) "edpd_cv edpd_temp vest vest_temp"; + fields_create = (char *) "edpd_cv edpd_temp edpd_flux vest vest_temp"; fields_data_atom = (char *) "id type edpd_temp edpd_cv x"; fields_data_vel = (char *) "id v"; @@ -85,7 +85,7 @@ void AtomVecEDPD::create_atom_post(int ilocal) { atom->edpd_temp[ilocal] = 1.0; atom->edpd_cv[ilocal]= 1.0e5; - atom->vest[ilocal][3] = atom->edpd_temp[ilocal]; + atom->vest_temp[ilocal] = atom->edpd_temp[ilocal]; } /* ---------------------------------------------------------------------- @@ -99,5 +99,5 @@ void AtomVecEDPD::data_atom_post(int ilocal) atom->vest[ilocal][0] = 0.0; atom->vest[ilocal][1] = 0.0; atom->vest[ilocal][2] = 0.0; - atom->vest[ilocal][3] = atom->edpd_temp[ilocal]; + atom->vest_temp[ilocal] = atom->edpd_temp[ilocal]; } diff --git a/src/USER-MESO/atom_vec_tdpd.cpp b/src/USER-MESO/atom_vec_tdpd.cpp index 55284f69a2..5734fcf9ad 100644 --- a/src/USER-MESO/atom_vec_tdpd.cpp +++ b/src/USER-MESO/atom_vec_tdpd.cpp @@ -63,7 +63,7 @@ void AtomVecTDPD::process_args(int narg, char **arg) cc_species = atom->cc_species; atom->add_peratom_change_columns("cc",cc_species); - atom->add_peratom_change_columns("cc_species",cc_species); + atom->add_peratom_change_columns("cc_flux",cc_species); // delay setting up of fields until now diff --git a/src/USER-MESO/fix_mvv_edpd.cpp b/src/USER-MESO/fix_mvv_edpd.cpp index bd9cd9cc2a..3294d8d682 100644 --- a/src/USER-MESO/fix_mvv_edpd.cpp +++ b/src/USER-MESO/fix_mvv_edpd.cpp @@ -88,6 +88,7 @@ void FixMvvEDPD::initial_integrate(int /*vflag*/) double *edpd_flux = atom->edpd_flux; double *edpd_cv = atom->edpd_cv; double **vest = atom->vest; + double *vest_temp = atom->vest_temp; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; @@ -105,7 +106,7 @@ void FixMvvEDPD::initial_integrate(int /*vflag*/) vest[i][0] = v[i][0] + dtfm * f[i][0]; vest[i][1] = v[i][1] + dtfm * f[i][1]; vest[i][2] = v[i][2] + dtfm * f[i][2]; - vest[i][3] = edpd_temp[i] + dtT * edpd_flux[i]; + vest_temp[i] = edpd_temp[i] + dtT * edpd_flux[i]; x[i][0] += dtv * vest[i][0]; x[i][1] += dtv * vest[i][1]; @@ -131,6 +132,7 @@ void FixMvvEDPD::final_integrate() double *edpd_flux = atom->edpd_flux; double *edpd_cv = atom->edpd_cv; double **vest = atom->vest; + double *vest_temp = atom->vest_temp; double *rmass = atom->rmass; double *mass = atom->mass; int *type = atom->type; @@ -148,7 +150,7 @@ void FixMvvEDPD::final_integrate() v[i][0] = vest[i][0] + dtfm * f[i][0]; v[i][1] = vest[i][1] + dtfm * f[i][1]; v[i][2] = vest[i][2] + dtfm * f[i][2]; - edpd_temp[i] = vest[i][3] + dtT * edpd_flux[i]; + edpd_temp[i] = vest_temp[i] + dtT * edpd_flux[i]; } } diff --git a/src/USER-SMD/atom_vec_smd.cpp b/src/USER-SMD/atom_vec_smd.cpp index 0fada3dc2a..9f0ed04a09 100644 --- a/src/USER-SMD/atom_vec_smd.cpp +++ b/src/USER-SMD/atom_vec_smd.cpp @@ -63,7 +63,7 @@ AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) fields_grow = (char *) "de vfrac rmass x0 radius contact_radius molecule " - "smd_data_9 e vest tlsph_stress " + "smd_data_9 e vest smd_stress " "eff_plastic_strain eff_plastic_strain_rate damage"; fields_copy = (char *) "vfrac rmass x0 radius contact_radius molecule e " @@ -91,7 +91,7 @@ AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) "eff_plastic_strain eff_plastic_strain_rate smd_data_9 smd_stress damage"; fields_data_atom = (char *) "id type molecule vfrac rmass radius contact_radius x"; - fields_data_vel = (char *) "id v vest"; + fields_data_vel = (char *) "id v"; // set these array sizes based on defines diff --git a/src/atom.cpp b/src/atom.cpp index 8fd859478f..0fbee8f583 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -566,6 +566,7 @@ void Atom::peratom_create() add_peratom("edpd_cv",&edpd_cv,DOUBLE,0); add_peratom("edpd_temp",&edpd_temp,DOUBLE,0); + add_peratom("vest_temp",&vest_temp,DOUBLE,0); add_peratom("edpd_flux",&edpd_flux,DOUBLE,0,1); // set per-thread flag add_peratom("cc",&cc,DOUBLE,1); add_peratom("cc_flux",&cc_flux,DOUBLE,1,1); // set per-thread flag @@ -625,8 +626,11 @@ void Atom::add_peratom(const char *name, void *address, void Atom::add_peratom_change_columns(const char *name, int cols) { + int i; for (int i = 0; i < nperatom; i++) if (strcmp(name,peratom[i].name) == 0) peratom[i].cols = cols; + if (i == nperatom) + error->all(FLERR,"Could not find name of peratom array for column change"); } /* ---------------------------------------------------------------------- diff --git a/src/atom.h b/src/atom.h index 007d364a7b..bc1eb1a7d7 100644 --- a/src/atom.h +++ b/src/atom.h @@ -124,6 +124,7 @@ class Atom : protected Pointers { double **cc,**cc_flux; // cc = chemical concentration double *edpd_temp,*edpd_flux; // temperature and heat flux + double *vest_temp; double *edpd_cv; // heat capacity int cc_species; @@ -162,10 +163,6 @@ class Atom : protected Pointers { int sp_flag; - // USER-EFF package - - int ecp_flag; - // USER-SMD package int smd_flag; diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index bbfccadb89..e31c235760 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -45,6 +45,7 @@ AtomVec::AtomVec(LAMMPS *lmp) : Pointers(lmp) forceclearflag = 0; maxexchange = 0; bonus_flag = 0; + size_forward_bonus = size_border_bonus = 0; kokkosable = 0; @@ -176,7 +177,7 @@ int AtomVec::grow_nmax_bonus(int nmax_bonus) void AtomVec::grow(int n) { - int i,datatype,cols,maxcols; + int datatype,cols,maxcols; void *pdata,*plength; if (n == 0) grow_nmax(); @@ -193,7 +194,7 @@ void AtomVec::grow(int n) v = memory->grow(atom->v,nmax,3,"atom:v"); f = memory->grow(atom->f,nmax*nthreads,3,"atom:f"); - for (i = 0; i < ngrow; i++) { + for (int i = 0; i < ngrow; i++) { pdata = mgrow.pdata[i]; datatype = mgrow.datatype[i]; cols = mgrow.cols[i]; @@ -415,7 +416,7 @@ int AtomVec::pack_comm(int n, int *list, double *buf, /* ---------------------------------------------------------------------- */ int AtomVec::pack_comm_vel(int n, int *list, double *buf, - int pbc_flag, int *pbc) + int pbc_flag, int *pbc) { int i,j,m,mm,nn,datatype,cols; double dx,dy,dz,dvx,dvy,dvz; @@ -1375,15 +1376,15 @@ int AtomVec::size_restart() if (nrestart) { for (nn = 0; nn < nrestart; nn++) { - cols = mrestart.cols[i]; + cols = mrestart.cols[nn]; if (cols == 0) n += nlocal; else if (cols > 0) n += cols*nlocal; else { collength = mrestart.collength[nn]; plength = mrestart.plength[nn]; for (i = 0; i < nlocal; i++) { - if (collength) ncols = (*((int ***) plength))[nlocal][collength-1]; - else ncols = (*((int **) plength))[nlocal]; + if (collength) ncols = (*((int ***) plength))[i][collength-1]; + else ncols = (*((int **) plength))[i]; n += ncols; } } @@ -1435,7 +1436,7 @@ int AtomVec::pack_restart(int i, double *buf) if (cols == 0) { double *vec = *((double **) pdata); buf[m++] = vec[i]; - } else if (ncols > 0) { + } else if (cols > 0) { double **array = *((double ***) pdata); for (mm = 0; mm < cols; mm++) buf[m++] = array[i][mm]; @@ -1469,7 +1470,7 @@ int AtomVec::pack_restart(int i, double *buf) if (cols == 0) { bigint *vec = *((bigint **) pdata); buf[m++] = ubuf(vec[i]).d; - } else if (ncols > 0) { + } else if (cols > 0) { bigint **array = *((bigint ***) pdata); for (mm = 0; mm < cols; mm++) buf[m++] = ubuf(array[i][mm]).d; @@ -1705,7 +1706,7 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) vec[nlocal] = utils::numeric(FLERR,values[ivalue++],true,lmp); } else { double **array = *((double ***) pdata); - if (array == atom->x) { // already set by coord arg + if (array == atom->x) { // x was already set by coord arg ivalue += cols; continue; } @@ -1878,9 +1879,9 @@ void AtomVec::data_vel(int ilocal, char **values) v[ilocal][1] = utils::numeric(FLERR,values[1],true,lmp); v[ilocal][2] = utils::numeric(FLERR,values[2],true,lmp); - if (ndata_vel) { + if (ndata_vel > 2) { int ivalue = 3; - for (n = 0; n < ndata_vel; n++) { + for (n = 2; n < ndata_vel; n++) { pdata = mdata_vel.pdata[n]; datatype = mdata_vel.datatype[n]; cols = mdata_vel.cols[n]; @@ -2434,6 +2435,7 @@ void AtomVec::setup_fields() else size_data_atom += cols; } + size_data_vel = 0; for (n = 0; n < ndata_vel; n++) { cols = mdata_vel.cols[n]; diff --git a/src/atom_vec.h b/src/atom_vec.h index 69ea1d51ab..5911c8414b 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -74,7 +74,7 @@ class AtomVec : protected Pointers { virtual void force_clear(int, size_t) {} - void grow(int); + virtual void grow(int); void copy(int, int, int); virtual void copy_bonus(int, int, int) {} @@ -122,13 +122,11 @@ class AtomVec : protected Pointers { void data_atom(double *, imageint, char **); virtual void data_atom_post(int) {} - - void data_atom_bonus(int, char **) {} - void data_body(int, int, int, int *, double *) {} + virtual void data_atom_bonus(int, char **) {} + virtual void data_body(int, int, int, int *, double *) {} void pack_data(double **); void write_data(FILE *, int, double **); - virtual void pack_data_pre(int) {} virtual void pack_data_post(int) {} @@ -145,19 +143,19 @@ class AtomVec : protected Pointers { int pack_improper(tagint **); void write_improper(FILE *, int, tagint **, int); - int property_atom(char *) {return -1;} - void pack_property_atom(int, double *, int, int) {} + virtual int property_atom(char *) {return -1;} + virtual void pack_property_atom(int, double *, int, int) {} bigint memory_usage(); virtual bigint memory_usage_bonus() {} protected: - int nmax; // local copy of atom->nmax - int deform_vremap; // local copy of domain properties + int nmax; // local copy of atom->nmax + int deform_vremap; // local copy of domain properties int deform_groupbit; double *h_rate; - tagint *tag; // peratom fields common to all styles + tagint *tag; // peratom fields common to all styles int *type,*mask; imageint *image; double **x,**v,**f; diff --git a/src/atom_vec_body.cpp b/src/atom_vec_body.cpp index 19ac69cef3..a04f23a47c 100644 --- a/src/atom_vec_body.cpp +++ b/src/atom_vec_body.cpp @@ -40,8 +40,8 @@ AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp) // size_data_bonus is not used by Atom class for body style size_forward_bonus = 4; - size_border_bonus = 9; - size_restart_bonus_one = 9; + size_border_bonus = 10; + size_restart_bonus_one = 10; size_data_bonus = 0; atom->body_flag = 1; @@ -72,11 +72,9 @@ AtomVecBody::AtomVecBody(LAMMPS *lmp) : AtomVec(lmp) fields_border_vel = (char *) "radius rmass angmom"; fields_exchange = (char *) "radius rmass angmom"; fields_restart = (char *) "radius rmass angmom"; - fields_create = (char *) "radius rmass angmom tri"; + fields_create = (char *) "radius rmass angmom body"; fields_data_atom = (char *) "id type body rmass x"; fields_data_vel = (char *) "id v angmom"; - - setup_fields(); } /* ---------------------------------------------------------------------- */ @@ -127,6 +125,20 @@ void AtomVecBody::process_args(int narg, char **arg) size_forward_bonus += bptr->size_forward; size_border_bonus += bptr->size_border; + + setup_fields(); +} + +/* ---------------------------------------------------------------------- + grow atom arrays + must set local copy of body ptr + needed in replicate when 2 atom classes exist and pack_restart() is called +------------------------------------------------------------------------- */ + +void AtomVecBody::grow(int n) +{ + AtomVec::grow(n); + body = atom->body; } /* ---------------------------------------------------------------------- @@ -150,8 +162,6 @@ void AtomVecBody::grow_bonus() void AtomVecBody::copy_bonus(int i, int j, int delflag) { - int *body = atom->body; - // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && body[j] >= 0) { @@ -206,8 +216,6 @@ int AtomVecBody::pack_comm_bonus(int n, int *list, double *buf) int i,j,m; double *quat; - int *body = atom->body; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -231,8 +239,6 @@ void AtomVecBody::unpack_comm_bonus(int n, int first, double *buf) int i,m,last; double *quat; - int *body = atom->body; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -254,8 +260,6 @@ int AtomVecBody::pack_border_bonus(int n, int *list, double *buf) int i,j,m; double *quat,*inertia; - int *body = atom->body; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -287,8 +291,6 @@ int AtomVecBody::unpack_border_bonus(int n, int first, double *buf) int i,j,m,last; double *quat,*inertia; - int *body = atom->body; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -330,8 +332,6 @@ int AtomVecBody::pack_exchange_bonus(int i, double *buf) { int m = 0; - int *body = atom->body; - if (body[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -363,8 +363,6 @@ int AtomVecBody::unpack_exchange_bonus(int ilocal, double *buf) { int m = 0; - int *body = atom->body; - body[ilocal] = (int) ubuf(buf[m++]).i; if (body[ilocal] == 0) body[ilocal] = -1; else { @@ -408,8 +406,6 @@ int AtomVecBody::size_restart_bonus() { int i; - int *body = atom->body; - int n = 0; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { @@ -418,8 +414,7 @@ int AtomVecBody::size_restart_bonus() if (intdoubleratio == 1) n += bonus[body[i]].ninteger; else n += (bonus[body[i]].ninteger+1)/2; n += bonus[body[i]].ndouble; - } - n++; + } else n++; } return n; @@ -435,8 +430,6 @@ int AtomVecBody::pack_restart_bonus(int i, double *buf) { int m = 0; - int *body = atom->body; - if (body[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -470,8 +463,6 @@ int AtomVecBody::unpack_restart_bonus(int ilocal, double *buf) { int m = 0; - int *body = atom->body; - body[ilocal] = (int) ubuf(buf[m++]).i; if (body[ilocal] == 0) body[ilocal] = -1; else { diff --git a/src/atom_vec_body.h b/src/atom_vec_body.h index 939b01878d..3f32c8223c 100644 --- a/src/atom_vec_body.h +++ b/src/atom_vec_body.h @@ -43,6 +43,7 @@ class AtomVecBody : public AtomVec { ~AtomVecBody(); void process_args(int, char **); + void grow(int); void copy_bonus(int, int, int); void clear_bonus(); int pack_comm_bonus(int, int *, double *); @@ -74,6 +75,8 @@ class AtomVecBody : public AtomVec { int intdoubleratio; // sizeof(double) / sizeof(int) int body_flag; + int *body; + MyPoolChunk *icp; MyPoolChunk *dcp; diff --git a/src/atom_vec_ellipsoid.cpp b/src/atom_vec_ellipsoid.cpp index 9166293384..e8ab6d5613 100644 --- a/src/atom_vec_ellipsoid.cpp +++ b/src/atom_vec_ellipsoid.cpp @@ -38,7 +38,7 @@ AtomVecEllipsoid::AtomVecEllipsoid(LAMMPS *lmp) : AtomVec(lmp) size_forward_bonus = 4; size_border_bonus = 8; - size_restart_bonus_one = 7; + size_restart_bonus_one = 8; size_data_bonus = 8; atom->ellipsoid_flag = 1; @@ -320,7 +320,7 @@ int AtomVecEllipsoid::size_restart_bonus() int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (ellipsoid[i] >= 0) n += size_restart_bonus_one; - n++; + else n++; } return n; diff --git a/src/atom_vec_line.cpp b/src/atom_vec_line.cpp index ded2f88c2f..7ab697b349 100644 --- a/src/atom_vec_line.cpp +++ b/src/atom_vec_line.cpp @@ -37,7 +37,7 @@ AtomVecLine::AtomVecLine(LAMMPS *lmp) : AtomVec(lmp) size_forward_bonus = 1; size_border_bonus = 3; - size_restart_bonus_one = 2; + size_restart_bonus_one = 3; size_data_bonus = 5; atom->line_flag = 1; @@ -286,7 +286,7 @@ int AtomVecLine::size_restart_bonus() int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (line[i] >= 0) n += size_restart_bonus_one; - n++; + else n++; } return n; diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index 81f1b02fdb..b601fc8f7c 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -61,18 +61,22 @@ AtomVecSphere::AtomVecSphere(LAMMPS *lmp) : AtomVec(lmp) void AtomVecSphere::process_args(int narg, char **arg) { - if (narg == 0) return; - if (narg != 1) error->all(FLERR,"Illegal atom_style sphere command"); - - radvary = utils::numeric(FLERR,arg[0],true,lmp); - if (radvary < 0 || radvary > 1) + if (narg != 0 && narg != 1) error->all(FLERR,"Illegal atom_style sphere command"); - if (radvary == 0) return; + + radvary = 0; + if (narg == 1) { + radvary = utils::numeric(FLERR,arg[0],true,lmp); + if (radvary < 0 || radvary > 1) + error->all(FLERR,"Illegal atom_style sphere command"); + } // dynamic particle radius and mass must be communicated every step - fields_comm = (char *) "radius rmass"; - fields_comm_vel = (char *) "radius rmass omega"; + if (radvary) { + fields_comm = (char *) "radius rmass"; + fields_comm_vel = (char *) "radius rmass omega"; + } // delay setting up of fields until now diff --git a/src/atom_vec_tri.cpp b/src/atom_vec_tri.cpp index 32d75c16f3..7345646a1e 100644 --- a/src/atom_vec_tri.cpp +++ b/src/atom_vec_tri.cpp @@ -38,7 +38,7 @@ AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp) size_forward_bonus = 4; size_border_bonus = 17; - size_restart_bonus_one = 16; + size_restart_bonus_one = 17; size_data_bonus = 10; atom->tri_flag = 1; @@ -64,7 +64,7 @@ AtomVecTri::AtomVecTri(LAMMPS *lmp) : AtomVec(lmp) fields_border_vel = (char *) "molecule radius rmass omega"; fields_exchange = (char *) "molecule radius rmass omega angmom"; fields_restart = (char *) "molecule radius rmass omega angmom"; - fields_create = (char *) "molecule radius rmass omega angmom line"; + fields_create = (char *) "molecule radius rmass omega angmom tri"; fields_data_atom = (char *) "id molecule type tri rmass x"; fields_data_vel = (char *) "id v omega angmom"; @@ -381,7 +381,7 @@ int AtomVecTri::size_restart_bonus() int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { if (tri[i] >= 0) n += size_restart_bonus_one; - n++; + else n++; } return n; diff --git a/src/fix_gravity.cpp b/src/fix_gravity.cpp index 14ba913c01..e00bbb4e17 100644 --- a/src/fix_gravity.cpp +++ b/src/fix_gravity.cpp @@ -31,7 +31,7 @@ using namespace FixConst; using namespace MathConst; enum{CHUTE,SPHERICAL,VECTOR}; -enum{CONSTANT,EQUAL}; +enum{CONSTANT,EQUAL}; // same as FixPour /* ---------------------------------------------------------------------- */ @@ -134,6 +134,16 @@ FixGravity::FixGravity(LAMMPS *lmp, int narg, char **arg) : eflag = 0; egrav = 0.0; + + // set gravity components once and for all if CONSTANT + + varflag = CONSTANT; + if (mstyle != CONSTANT || vstyle != CONSTANT || pstyle != CONSTANT || + tstyle != CONSTANT || xstyle != CONSTANT || ystyle != CONSTANT || + zstyle != CONSTANT) varflag = EQUAL; + + if (varflag == CONSTANT) set_acceleration(); + } /* ---------------------------------------------------------------------- */ @@ -222,15 +232,6 @@ void FixGravity::init() if (!input->variable->equalstyle(zvar)) error->all(FLERR,"Variable for fix gravity is invalid style"); } - - varflag = CONSTANT; - if (mstyle != CONSTANT || vstyle != CONSTANT || pstyle != CONSTANT || - tstyle != CONSTANT || xstyle != CONSTANT || ystyle != CONSTANT || - zstyle != CONSTANT) varflag = EQUAL; - - // set gravity components once and for all - - if (varflag == CONSTANT) set_acceleration(); } /* ---------------------------------------------------------------------- */ diff --git a/src/replicate.cpp b/src/replicate.cpp index 1617ab0313..3659f7cf7a 100644 --- a/src/replicate.cpp +++ b/src/replicate.cpp @@ -331,35 +331,43 @@ void Replicate::command(int narg, char **arg) if (me == 0 && screen) { fprintf(screen," bounding box image = (%i %i %i) to (%i %i %i)\n", - _imagelo[0],_imagelo[1],_imagelo[2],_imagehi[0],_imagehi[1],_imagehi[2]); + _imagelo[0],_imagelo[1],_imagelo[2], + _imagehi[0],_imagehi[1],_imagehi[2]); fprintf(screen," bounding box extra memory = %.2f MB\n", (double)size_buf_all*sizeof(double)/1024/1024); } // rnk offsets - int * disp_buf_rnk; + int *disp_buf_rnk; memory->create(disp_buf_rnk, nprocs, "replicate:disp_buf_rnk"); disp_buf_rnk[0] = 0; - for (i=1; icreate(buf_all, size_buf_all, "replicate:buf_all"); - MPI_Allgatherv(buf, n, MPI_DOUBLE, buf_all, size_buf_rnk, disp_buf_rnk, MPI_DOUBLE, world); + MPI_Allgatherv(buf,n,MPI_DOUBLE,buf_all,size_buf_rnk,disp_buf_rnk, + MPI_DOUBLE,world); // bounding box of original unwrapped system double _orig_lo[3], _orig_hi[3]; if (triclinic) { - _orig_lo[0] = domain->boxlo[0] + _imagelo[0] * old_xprd + _imagelo[1] * old_xy + _imagelo[2] * old_xz; - _orig_lo[1] = domain->boxlo[1] + _imagelo[1] * old_yprd + _imagelo[2] * old_yz; + _orig_lo[0] = domain->boxlo[0] + + _imagelo[0] * old_xprd + _imagelo[1] * old_xy + _imagelo[2] * old_xz; + _orig_lo[1] = domain->boxlo[1] + + _imagelo[1] * old_yprd + _imagelo[2] * old_yz; _orig_lo[2] = domain->boxlo[2] + _imagelo[2] * old_zprd; - _orig_hi[0] = domain->boxlo[0] + (_imagehi[0]+1) * old_xprd + (_imagehi[1]+1) * old_xy + (_imagehi[2]+1) * old_xz; - _orig_hi[1] = domain->boxlo[1] + (_imagehi[1]+1) * old_yprd + (_imagehi[2]+1) * old_yz; + _orig_hi[0] = domain->boxlo[0] + + (_imagehi[0]+1) * old_xprd + + (_imagehi[1]+1) * old_xy + (_imagehi[2]+1) * old_xz; + _orig_hi[1] = domain->boxlo[1] + + (_imagehi[1]+1) * old_yprd + (_imagehi[2]+1) * old_yz; _orig_hi[2] = domain->boxlo[2] + (_imagehi[2]+1) * old_zprd; } else { _orig_lo[0] = domain->boxlo[0] + _imagelo[0] * old_xprd; @@ -605,7 +613,8 @@ void Replicate::command(int narg, char **arg) MPI_Reduce(&num_replicas_added, &sum, 1, MPI_INT, MPI_SUM, 0, world); double avg = (double) sum / nprocs; if (me == 0 && screen) - fprintf(screen," average # of replicas added to proc = %.2f out of %i (%.2f %%)\n", + fprintf(screen," average # of replicas added to proc = %.2f " + "out of %i (%.2f %%)\n", avg,nx*ny*nz,avg/(nx*ny*nz)*100.0); } else { diff --git a/src/verlet.cpp b/src/verlet.cpp index 8cd6fe940d..fe9645618a 100644 --- a/src/verlet.cpp +++ b/src/verlet.cpp @@ -109,7 +109,7 @@ void Verlet::setup(int flag) domain->pbc(); domain->reset_box(); comm->setup(); - if (neighbor->style) neighbor->setup_bins(); + if (neighbor->style) neighbor->setup_bins(); comm->exchange(); if (atom->sortfreq > 0) atom->sort(); comm->borders(); -- GitLab From b6374bacfb13a4b9c7273c2d07dd5dd1dd055ba0 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 18 Dec 2019 08:56:03 -0700 Subject: [PATCH 014/577] enable replicate to work with local ptrs --- src/DIPOLE/atom_vec_dipole.cpp | 15 +++- src/DIPOLE/atom_vec_dipole.h | 5 ++ src/MOLECULE/atom_vec_angle.cpp | 39 +++++---- src/MOLECULE/atom_vec_angle.h | 6 ++ src/MOLECULE/atom_vec_bond.cpp | 29 +++---- src/MOLECULE/atom_vec_bond.h | 10 ++- src/MOLECULE/atom_vec_full.cpp | 55 ++++++------- src/MOLECULE/atom_vec_full.h | 6 ++ src/MOLECULE/atom_vec_molecular.cpp | 55 ++++++------- src/MOLECULE/atom_vec_molecular.h | 6 ++ src/MOLECULE/atom_vec_template.cpp | 23 ++++-- src/MOLECULE/atom_vec_template.h | 5 ++ src/PERI/atom_vec_peri.cpp | 37 ++++++--- src/PERI/atom_vec_peri.h | 7 ++ src/SPIN/atom_vec_spin.cpp | 29 +++++-- src/SPIN/atom_vec_spin.h | 5 ++ src/USER-DPD/atom_vec_dpd.cpp | 36 ++++++--- src/USER-DPD/atom_vec_dpd.h | 7 ++ src/USER-EFF/atom_vec_electron.cpp | 25 ++++-- src/USER-EFF/atom_vec_electron.h | 6 ++ src/USER-MESO/atom_vec_edpd.cpp | 32 +++++--- src/USER-MESO/atom_vec_edpd.h | 7 ++ src/USER-MESO/atom_vec_mdpd.cpp | 24 ++++-- src/USER-MESO/atom_vec_mdpd.h | 6 ++ src/USER-MESO/atom_vec_tdpd.cpp | 14 +++- src/USER-MESO/atom_vec_tdpd.h | 5 ++ src/USER-SMD/atom_vec_smd.cpp | 92 +++++++++++++--------- src/USER-SMD/atom_vec_smd.h | 8 ++ src/USER-SPH/atom_vec_meso.cpp | 36 ++++++--- src/USER-SPH/atom_vec_meso.h | 6 ++ src/atom.cpp | 83 +++++++------------ src/atom.h | 15 ++-- src/atom_vec.cpp | 6 +- src/atom_vec.h | 3 +- src/atom_vec_body.cpp | 58 ++++++++------ src/atom_vec_body.h | 6 +- src/atom_vec_ellipsoid.cpp | 61 ++++++-------- src/atom_vec_ellipsoid.h | 6 +- src/atom_vec_hybrid.cpp | 16 ++-- src/atom_vec_hybrid.h | 3 +- src/atom_vec_line.cpp | 95 ++++++++++------------ src/atom_vec_line.h | 7 +- src/atom_vec_sphere.cpp | 45 +++++++---- src/atom_vec_sphere.h | 6 +- src/atom_vec_tri.cpp | 118 +++++++++++++--------------- src/atom_vec_tri.h | 7 +- src/replicate.cpp | 3 +- 47 files changed, 690 insertions(+), 484 deletions(-) diff --git a/src/DIPOLE/atom_vec_dipole.cpp b/src/DIPOLE/atom_vec_dipole.cpp index 5cdbab1b33..074a59d5a1 100644 --- a/src/DIPOLE/atom_vec_dipole.cpp +++ b/src/DIPOLE/atom_vec_dipole.cpp @@ -54,6 +54,16 @@ AtomVecDipole::AtomVecDipole(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecDipole::grow_pointers() +{ + mu = atom->mu; +} + /* ---------------------------------------------------------------------- modify what AtomVec::data_atom() just unpacked or initialize other atom quantities @@ -61,6 +71,7 @@ AtomVecDipole::AtomVecDipole(LAMMPS *lmp) : AtomVec(lmp) void AtomVecDipole::data_atom_post(int ilocal) { - double *mu = atom->mu[ilocal]; - mu[3] = sqrt(mu[0]*mu[0] + mu[1]*mu[1] + mu[2]*mu[2]); + double *mu_one = mu[ilocal]; + mu_one[3] = + sqrt(mu_one[0]*mu_one[0] + mu_one[1]*mu_one[1] + mu_one[2]*mu_one[2]); } diff --git a/src/DIPOLE/atom_vec_dipole.h b/src/DIPOLE/atom_vec_dipole.h index 45f33d109d..2030892a43 100644 --- a/src/DIPOLE/atom_vec_dipole.h +++ b/src/DIPOLE/atom_vec_dipole.h @@ -27,7 +27,12 @@ namespace LAMMPS_NS { class AtomVecDipole : public AtomVec { public: AtomVecDipole(class LAMMPS *); + + void grow_pointers(); void data_atom_post(int); + + private: + double **mu; }; } diff --git a/src/MOLECULE/atom_vec_angle.cpp b/src/MOLECULE/atom_vec_angle.cpp index 1bd6f9a071..f3ebe3258b 100644 --- a/src/MOLECULE/atom_vec_angle.cpp +++ b/src/MOLECULE/atom_vec_angle.cpp @@ -66,6 +66,20 @@ AtomVecAngle::~AtomVecAngle() delete [] angle_negative; } +/* ---------------------------------------------------------------------- + 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 AtomVecAngle::grow_pointers() +{ + num_bond = atom->num_bond; + bond_type = atom->bond_type; + num_angle = atom->num_angle; + angle_type = atom->angle_type; + nspecial = atom->nspecial; +} + /* ---------------------------------------------------------------------- modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ @@ -87,11 +101,6 @@ void AtomVecAngle::pack_restart_pre(int ilocal) // flip any negative types to positive and flag which ones - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; - int *num_angle = atom->num_angle; - int **angle_type = atom->angle_type; - int any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { if (bond_type[ilocal][m] < 0) { @@ -120,15 +129,11 @@ void AtomVecAngle::pack_restart_post(int ilocal) // restore the flagged types to their negative values if (any_bond_negative) { - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[ilocal]; m++) if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } if (any_angle_negative) { - int *num_angle = atom->num_angle; - int **angle_type = atom->angle_type; for (int m = 0; m < num_angle[ilocal]; m++) if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m]; } @@ -140,9 +145,9 @@ void AtomVecAngle::pack_restart_post(int ilocal) void AtomVecAngle::unpack_restart_init(int ilocal) { - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- @@ -152,9 +157,9 @@ void AtomVecAngle::unpack_restart_init(int ilocal) void AtomVecAngle::data_atom_post(int ilocal) { - atom->num_bond[ilocal] = 0; - atom->num_angle[ilocal] = 0; - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + num_bond[ilocal] = 0; + num_angle[ilocal] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_angle.h b/src/MOLECULE/atom_vec_angle.h index 48e55b0988..0ce0b4baab 100644 --- a/src/MOLECULE/atom_vec_angle.h +++ b/src/MOLECULE/atom_vec_angle.h @@ -28,12 +28,18 @@ class AtomVecAngle : public AtomVec { public: AtomVecAngle(class LAMMPS *); ~AtomVecAngle(); + + void grow_pointers(); void pack_restart_pre(int); void pack_restart_post(int); void unpack_restart_init(int); void data_atom_post(int); private: + int *num_bond,*num_angle; + int **bond_type,**angle_type; + int **nspecial; + int any_bond_negative,any_angle_negative; int bond_per_atom,angle_per_atom; int *bond_negative,*angle_negative; diff --git a/src/MOLECULE/atom_vec_bond.cpp b/src/MOLECULE/atom_vec_bond.cpp index 00e8e3260d..64a52fa80a 100644 --- a/src/MOLECULE/atom_vec_bond.cpp +++ b/src/MOLECULE/atom_vec_bond.cpp @@ -61,19 +61,17 @@ AtomVecBond::~AtomVecBond() } /* ---------------------------------------------------------------------- - grow atom arrays - must set local copy of body ptr - needed in replicate when 2 atom classes exist and pack_restart() is called + 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 AtomVecBond::grow(int n) +void AtomVecBond::grow_pointers() { - AtomVec::grow(n); num_bond = atom->num_bond; bond_type = atom->bond_type; + nspecial = atom->nspecial; } - /* ---------------------------------------------------------------------- modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ @@ -90,9 +88,6 @@ void AtomVecBond::pack_restart_pre(int ilocal) // flip any negative types to positive and flag which ones - //int *num_bond = atom->num_bond; - //int **bond_type = atom->bond_type; - any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { if (bond_type[ilocal][m] < 0) { @@ -112,8 +107,6 @@ void AtomVecBond::pack_restart_post(int ilocal) // restore the flagged types to their negative values if (any_bond_negative) { - //int *num_bond = atom->num_bond; - //int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[ilocal]; m++) if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } @@ -125,9 +118,9 @@ void AtomVecBond::pack_restart_post(int ilocal) void AtomVecBond::unpack_restart_init(int ilocal) { - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- @@ -137,8 +130,8 @@ void AtomVecBond::unpack_restart_init(int ilocal) void AtomVecBond::data_atom_post(int ilocal) { - atom->num_bond[ilocal] = 0; - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + num_bond[ilocal] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_bond.h b/src/MOLECULE/atom_vec_bond.h index 90c4b1f217..c938655127 100644 --- a/src/MOLECULE/atom_vec_bond.h +++ b/src/MOLECULE/atom_vec_bond.h @@ -28,19 +28,21 @@ class AtomVecBond : public AtomVec { public: AtomVecBond(class LAMMPS *); ~AtomVecBond(); - void grow(int); + + void grow_pointers(); void pack_restart_pre(int); void pack_restart_post(int); void unpack_restart_init(int); void data_atom_post(int); private: + int *num_bond; + int **bond_type; + int **nspecial; + int any_bond_negative; int bond_per_atom; int *bond_negative; - - int *num_bond; - int **bond_type; }; } diff --git a/src/MOLECULE/atom_vec_full.cpp b/src/MOLECULE/atom_vec_full.cpp index be7c92ce93..89afae5005 100644 --- a/src/MOLECULE/atom_vec_full.cpp +++ b/src/MOLECULE/atom_vec_full.cpp @@ -88,6 +88,24 @@ AtomVecFull::~AtomVecFull() delete [] improper_negative; } +/* ---------------------------------------------------------------------- + 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 AtomVecFull::grow_pointers() +{ + num_bond = atom->num_bond; + bond_type = atom->bond_type; + num_angle = atom->num_angle; + angle_type = atom->angle_type; + num_dihedral = atom->num_dihedral; + dihedral_type = atom->dihedral_type; + num_improper = atom->num_improper; + improper_type = atom->improper_type; + nspecial = atom->nspecial; +} + /* ---------------------------------------------------------------------- modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ @@ -119,15 +137,6 @@ void AtomVecFull::pack_restart_pre(int ilocal) // flip any negative types to positive and flag which ones - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; - int *num_angle = atom->num_angle; - int **angle_type = atom->angle_type; - int *num_dihedral = atom->num_dihedral; - int **dihedral_type = atom->dihedral_type; - int *num_improper = atom->num_improper; - int **improper_type = atom->improper_type; - any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { if (bond_type[ilocal][m] < 0) { @@ -174,30 +183,22 @@ void AtomVecFull::pack_restart_post(int ilocal) // restore the flagged types to their negative values if (any_bond_negative) { - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[ilocal]; m++) if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } if (any_angle_negative) { - int *num_angle = atom->num_angle; - int **angle_type = atom->angle_type; for (int m = 0; m < num_angle[ilocal]; m++) if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m]; } if (any_dihedral_negative) { - int *num_dihedral = atom->num_dihedral; - int **dihedral_type = atom->dihedral_type; for (int m = 0; m < num_dihedral[ilocal]; m++) if (dihedral_negative[m]) dihedral_type[ilocal][m] = -dihedral_type[ilocal][m]; } if (any_improper_negative) { - int *num_improper = atom->num_improper; - int **improper_type = atom->improper_type; for (int m = 0; m < num_improper[ilocal]; m++) if (improper_negative[m]) improper_type[ilocal][m] = -improper_type[ilocal][m]; @@ -210,9 +211,9 @@ void AtomVecFull::pack_restart_post(int ilocal) void AtomVecFull::unpack_restart_init(int ilocal) { - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- @@ -222,11 +223,11 @@ void AtomVecFull::unpack_restart_init(int ilocal) void AtomVecFull::data_atom_post(int ilocal) { - atom->num_bond[ilocal] = 0; - atom->num_angle[ilocal] = 0; - atom->num_dihedral[ilocal] = 0; - atom->num_improper[ilocal] = 0; - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + num_bond[ilocal] = 0; + num_angle[ilocal] = 0; + num_dihedral[ilocal] = 0; + num_improper[ilocal] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_full.h b/src/MOLECULE/atom_vec_full.h index 455bbd0d5e..1abd3351d3 100644 --- a/src/MOLECULE/atom_vec_full.h +++ b/src/MOLECULE/atom_vec_full.h @@ -28,12 +28,18 @@ class AtomVecFull : public AtomVec { public: AtomVecFull(class LAMMPS *); ~AtomVecFull(); + + void grow_pointers(); void pack_restart_pre(int); void pack_restart_post(int); void unpack_restart_init(int); void data_atom_post(int); private: + int *num_bond,*num_angle,*num_dihedral,*num_improper; + int **bond_type,**angle_type,**dihedral_type,**improper_type; + int **nspecial; + int any_bond_negative,any_angle_negative, any_dihedral_negative,any_improper_negative; int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; diff --git a/src/MOLECULE/atom_vec_molecular.cpp b/src/MOLECULE/atom_vec_molecular.cpp index ea15216aee..c2b71468c0 100644 --- a/src/MOLECULE/atom_vec_molecular.cpp +++ b/src/MOLECULE/atom_vec_molecular.cpp @@ -88,6 +88,24 @@ AtomVecMolecular::~AtomVecMolecular() delete [] improper_negative; } +/* ---------------------------------------------------------------------- + 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 AtomVecMolecular::grow_pointers() +{ + num_bond = atom->num_bond; + bond_type = atom->bond_type; + num_angle = atom->num_angle; + angle_type = atom->angle_type; + num_dihedral = atom->num_dihedral; + dihedral_type = atom->dihedral_type; + num_improper = atom->num_improper; + improper_type = atom->improper_type; + nspecial = atom->nspecial; +} + /* ---------------------------------------------------------------------- modify values for AtomVec::pack_restart() to pack ------------------------------------------------------------------------- */ @@ -119,15 +137,6 @@ void AtomVecMolecular::pack_restart_pre(int ilocal) // flip any negative types to positive and flag which ones - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; - int *num_angle = atom->num_angle; - int **angle_type = atom->angle_type; - int *num_dihedral = atom->num_dihedral; - int **dihedral_type = atom->dihedral_type; - int *num_improper = atom->num_improper; - int **improper_type = atom->improper_type; - any_bond_negative = 0; for (int m = 0; m < num_bond[ilocal]; m++) { if (bond_type[ilocal][m] < 0) { @@ -174,30 +183,22 @@ void AtomVecMolecular::pack_restart_post(int ilocal) // restore the flagged types to their negative values if (any_bond_negative) { - int *num_bond = atom->num_bond; - int **bond_type = atom->bond_type; for (int m = 0; m < num_bond[ilocal]; m++) if (bond_negative[m]) bond_type[ilocal][m] = -bond_type[ilocal][m]; } if (any_angle_negative) { - int *num_angle = atom->num_angle; - int **angle_type = atom->angle_type; for (int m = 0; m < num_angle[ilocal]; m++) if (angle_negative[m]) angle_type[ilocal][m] = -angle_type[ilocal][m]; } if (any_dihedral_negative) { - int *num_dihedral = atom->num_dihedral; - int **dihedral_type = atom->dihedral_type; for (int m = 0; m < num_dihedral[ilocal]; m++) if (dihedral_negative[m]) dihedral_type[ilocal][m] = -dihedral_type[ilocal][m]; } if (any_improper_negative) { - int *num_improper = atom->num_improper; - int **improper_type = atom->improper_type; for (int m = 0; m < num_improper[ilocal]; m++) if (improper_negative[m]) improper_type[ilocal][m] = -improper_type[ilocal][m]; @@ -210,9 +211,9 @@ void AtomVecMolecular::pack_restart_post(int ilocal) void AtomVecMolecular::unpack_restart_init(int ilocal) { - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } /* ---------------------------------------------------------------------- @@ -222,11 +223,11 @@ void AtomVecMolecular::unpack_restart_init(int ilocal) void AtomVecMolecular::data_atom_post(int ilocal) { - atom->num_bond[ilocal] = 0; - atom->num_angle[ilocal] = 0; - atom->num_dihedral[ilocal] = 0; - atom->num_improper[ilocal] = 0; - atom->nspecial[ilocal][0] = 0; - atom->nspecial[ilocal][1] = 0; - atom->nspecial[ilocal][2] = 0; + num_bond[ilocal] = 0; + num_angle[ilocal] = 0; + num_dihedral[ilocal] = 0; + num_improper[ilocal] = 0; + nspecial[ilocal][0] = 0; + nspecial[ilocal][1] = 0; + nspecial[ilocal][2] = 0; } diff --git a/src/MOLECULE/atom_vec_molecular.h b/src/MOLECULE/atom_vec_molecular.h index 5b79f8b5c6..bcfa13d9d3 100644 --- a/src/MOLECULE/atom_vec_molecular.h +++ b/src/MOLECULE/atom_vec_molecular.h @@ -28,12 +28,18 @@ class AtomVecMolecular : public AtomVec { public: AtomVecMolecular(class LAMMPS *); ~AtomVecMolecular(); + + void grow_pointers(); void pack_restart_pre(int); void pack_restart_post(int); void unpack_restart_init(int); void data_atom_post(int); private: + int *num_bond,*num_angle,*num_dihedral,*num_improper; + int **bond_type,**angle_type,**dihedral_type,**improper_type; + int **nspecial; + int any_bond_negative,any_angle_negative, any_dihedral_negative,any_improper_negative; int bond_per_atom,angle_per_atom,dihedral_per_atom,improper_per_atom; diff --git a/src/MOLECULE/atom_vec_template.cpp b/src/MOLECULE/atom_vec_template.cpp index 546c19da12..97d4c865ba 100644 --- a/src/MOLECULE/atom_vec_template.cpp +++ b/src/MOLECULE/atom_vec_template.cpp @@ -96,14 +96,25 @@ void AtomVecTemplate::process_args(int narg, char **arg) } } +/* ---------------------------------------------------------------------- + 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 AtomVecTemplate::grow_pointers() +{ + molindex = atom->molindex; + molatom = atom->molatom; +} + /* ---------------------------------------------------------------------- initialize non-zero atom quantities ------------------------------------------------------------------------- */ void AtomVecTemplate::create_atom_post(int ilocal) { - atom->molindex[ilocal] = -1; - atom->molatom[ilocal] = -1; + molindex[ilocal] = -1; + molatom[ilocal] = -1; } /* ---------------------------------------------------------------------- @@ -113,11 +124,11 @@ void AtomVecTemplate::create_atom_post(int ilocal) void AtomVecTemplate::data_atom_post(int ilocal) { - int molindex = atom->molindex[ilocal]; - int molatom = atom->molatom[ilocal]; + int molindex_one = molindex[ilocal]; + int molatom_one = molatom[ilocal]; - if (molindex < 0 || molindex >= nset) + if (molindex_one < 0 || molindex_one >= nset) error->one(FLERR,"Invalid template index in Atoms section of data file"); - if (molatom < 0 || molatom >= onemols[molindex]->natoms) + if (molatom_one < 0 || molatom_one >= onemols[molindex_one]->natoms) error->one(FLERR,"Invalid template atom in Atoms section of data file"); } diff --git a/src/MOLECULE/atom_vec_template.h b/src/MOLECULE/atom_vec_template.h index 52ef5e70e1..3bf2ec6273 100644 --- a/src/MOLECULE/atom_vec_template.h +++ b/src/MOLECULE/atom_vec_template.h @@ -27,9 +27,14 @@ namespace LAMMPS_NS { class AtomVecTemplate : public AtomVec { public: AtomVecTemplate(class LAMMPS *); + + void grow_pointers(); void process_args(int, char **); void create_atom_post(int); void data_atom_post(int); + + private: + int *molindex,*molatom; }; } diff --git a/src/PERI/atom_vec_peri.cpp b/src/PERI/atom_vec_peri.cpp index 58ff9c54d9..46d03c35eb 100644 --- a/src/PERI/atom_vec_peri.cpp +++ b/src/PERI/atom_vec_peri.cpp @@ -69,18 +69,31 @@ AtomVecPeri::AtomVecPeri(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecPeri::grow_pointers() +{ + rmass = atom->rmass; + vfrac = atom->vfrac; + s0 = atom->s0; + x0 = atom->x0; +} + /* ---------------------------------------------------------------------- initialize non-zero atom quantities ------------------------------------------------------------------------- */ void AtomVecPeri::create_atom_post(int ilocal) { - atom->vfrac[ilocal] = 1.0; - atom->rmass[ilocal] = 1.0; - atom->s0[ilocal] = DBL_MAX; - atom->x0[ilocal][0] = atom->x[ilocal][0]; - atom->x0[ilocal][1] = atom->x[ilocal][1]; - atom->x0[ilocal][2] = atom->x[ilocal][2]; + vfrac[ilocal] = 1.0; + rmass[ilocal] = 1.0; + s0[ilocal] = DBL_MAX; + x0[ilocal][0] = x[ilocal][0]; + x0[ilocal][1] = x[ilocal][1]; + x0[ilocal][2] = x[ilocal][2]; } /* ---------------------------------------------------------------------- @@ -90,12 +103,12 @@ void AtomVecPeri::create_atom_post(int ilocal) void AtomVecPeri::data_atom_post(int ilocal) { - atom->s0[ilocal] = DBL_MAX; - atom->x0[ilocal][0] = atom->x[ilocal][0]; - atom->x0[ilocal][1] = atom->x[ilocal][1]; - atom->x0[ilocal][2] = atom->x[ilocal][2]; + s0[ilocal] = DBL_MAX; + x0[ilocal][0] = x[ilocal][0]; + x0[ilocal][1] = x[ilocal][1]; + x0[ilocal][2] = x[ilocal][2]; - if (atom->rmass[ilocal] <= 0.0) + if (rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid mass in Atoms section of data file"); } @@ -124,14 +137,12 @@ void AtomVecPeri::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { - double *vfrac = atom->vfrac; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = vfrac[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 1) { - double *s0 = atom->s0; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = s0[i]; else buf[n] = 0.0; diff --git a/src/PERI/atom_vec_peri.h b/src/PERI/atom_vec_peri.h index 13a62eb194..5739ea55c1 100644 --- a/src/PERI/atom_vec_peri.h +++ b/src/PERI/atom_vec_peri.h @@ -27,10 +27,17 @@ namespace LAMMPS_NS { class AtomVecPeri : public AtomVec { public: AtomVecPeri(class LAMMPS *); + + void grow_pointers(); void create_atom_post(int); void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); + + private: + double *rmass,*vfrac,*s0; + double **x0; + }; } diff --git a/src/SPIN/atom_vec_spin.cpp b/src/SPIN/atom_vec_spin.cpp index 638a3b8021..1e745fd0c1 100644 --- a/src/SPIN/atom_vec_spin.cpp +++ b/src/SPIN/atom_vec_spin.cpp @@ -61,6 +61,18 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecSpin::grow_pointers() +{ + sp = atom->sp; + fm = atom->fm; + fm_long = atom->fm_long; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -69,9 +81,9 @@ AtomVecSpin::AtomVecSpin(LAMMPS *lmp) : AtomVec(lmp) void AtomVecSpin::force_clear(int n, size_t nbytes) { - memset(&atom->f[n][0],0,3*nbytes); - memset(&atom->fm[n][0],0,3*nbytes); - memset(&atom->fm_long[n][0],0,3*nbytes); + memset(&f[n][0],0,3*nbytes); + memset(&fm[n][0],0,3*nbytes); + memset(&fm_long[n][0],0,3*nbytes); } /* ---------------------------------------------------------------------- @@ -81,9 +93,10 @@ void AtomVecSpin::force_clear(int n, size_t nbytes) void AtomVecSpin::data_atom_post(int ilocal) { - double *sp = atom->sp[ilocal]; - double inorm = 1.0/sqrt(sp[0]*sp[0] + sp[1]*sp[1] + sp[2]*sp[2]); - sp[0] *= inorm; - sp[1] *= inorm; - sp[2] *= inorm; + double *sp_one = sp[ilocal]; + double norm = + 1.0/sqrt(sp_one[0]*sp_one[0] + sp_one[1]*sp_one[1] + sp_one[2]*sp_one[2]); + sp_one[0] *= norm; + sp_one[1] *= norm; + sp_one[2] *= norm; } diff --git a/src/SPIN/atom_vec_spin.h b/src/SPIN/atom_vec_spin.h index c68f3a0419..f24791605d 100644 --- a/src/SPIN/atom_vec_spin.h +++ b/src/SPIN/atom_vec_spin.h @@ -27,8 +27,13 @@ namespace LAMMPS_NS { class AtomVecSpin : public AtomVec { public: AtomVecSpin(class LAMMPS *); + + void grow_pointers(); void force_clear(int, size_t); void data_atom_post(int); + + private: + double **sp,**fm,**fm_long; }; } diff --git a/src/USER-DPD/atom_vec_dpd.cpp b/src/USER-DPD/atom_vec_dpd.cpp index 124a081191..34efd9bc2b 100644 --- a/src/USER-DPD/atom_vec_dpd.cpp +++ b/src/USER-DPD/atom_vec_dpd.cpp @@ -52,14 +52,30 @@ AtomVecDPD::AtomVecDPD(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecDPD::grow_pointers() +{ + rho = atom->rho; + dpdTheta = atom->dpdTheta; + uCond = atom->uCond; + uMech = atom->uMech; + uChem = atom->uChem; + uCG = atom->uCG; + uCGnew = atom->uCGnew; +} + /* ---------------------------------------------------------------------- initialize other atom quantities after AtomVec::unpack_restart() ------------------------------------------------------------------------- */ void AtomVecDPD::unpack_restart_init(int ilocal) { - atom->uCG[ilocal] = 0.0; - atom->uCGnew[ilocal] = 0.0; + uCG[ilocal] = 0.0; + uCGnew[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -69,14 +85,14 @@ void AtomVecDPD::unpack_restart_init(int ilocal) void AtomVecDPD::data_atom_post(int ilocal) { - atom->rho[ilocal] = 0.0; - atom->uCond[ilocal] = 0.0; - atom->uMech[ilocal] = 0.0; - atom->uChem[ilocal] = 0.0; - atom->uCG[ilocal] = 0.0; - atom->uCGnew[ilocal] = 0.0; - - if (atom->dpdTheta[ilocal] <= 0) + rho[ilocal] = 0.0; + uCond[ilocal] = 0.0; + uMech[ilocal] = 0.0; + uChem[ilocal] = 0.0; + uCG[ilocal] = 0.0; + uCGnew[ilocal] = 0.0; + + if (dpdTheta[ilocal] <= 0) error->one(FLERR,"Internal temperature in Atoms section of date file " "must be > zero"); } diff --git a/src/USER-DPD/atom_vec_dpd.h b/src/USER-DPD/atom_vec_dpd.h index 20c8a9a2d2..61abc658b8 100644 --- a/src/USER-DPD/atom_vec_dpd.h +++ b/src/USER-DPD/atom_vec_dpd.h @@ -27,8 +27,15 @@ namespace LAMMPS_NS { class AtomVecDPD : public AtomVec { public: AtomVecDPD(class LAMMPS *); + + void grow_pointers(); void unpack_restart_init(int); void data_atom_post(int); + +private: + double *rho,*dpdTheta; + double *uCond,*uMech,*uChem; + double *uCG,*uCGnew; }; } diff --git a/src/USER-EFF/atom_vec_electron.cpp b/src/USER-EFF/atom_vec_electron.cpp index 0ac56c48a3..0912fb0498 100644 --- a/src/USER-EFF/atom_vec_electron.cpp +++ b/src/USER-EFF/atom_vec_electron.cpp @@ -69,6 +69,19 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecElectron::grow_pointers() +{ + spin = atom->spin; + eradius = atom->eradius; + ervel = atom->ervel; + erforce = atom->erforce; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -76,7 +89,7 @@ AtomVecElectron::AtomVecElectron(LAMMPS *lmp) : AtomVec(lmp) void AtomVecElectron::force_clear(int n, size_t nbytes) { - memset(&atom->erforce[n],0,nbytes); + memset(&erforce[n],0,nbytes); } /* ---------------------------------------------------------------------- @@ -85,8 +98,8 @@ void AtomVecElectron::force_clear(int n, size_t nbytes) void AtomVecElectron::create_atom_post(int ilocal) { - atom->spin[ilocal] = 1; - atom->eradius[ilocal] = 1.0; + spin[ilocal] = 1; + eradius[ilocal] = 1.0; } /* ---------------------------------------------------------------------- @@ -96,7 +109,7 @@ void AtomVecElectron::create_atom_post(int ilocal) void AtomVecElectron::data_atom_post(int ilocal) { - atom->ervel[ilocal] = 0.0; + ervel[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -126,28 +139,24 @@ void AtomVecElectron::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { - int *spin = atom->spin; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = spin[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 1) { - double *eradius = atom->eradius; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = eradius[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 2) { - double *ervel = atom->ervel; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = ervel[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 3) { - double *erforce = atom->erforce; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = erforce[i]; else buf[n] = 0.0; diff --git a/src/USER-EFF/atom_vec_electron.h b/src/USER-EFF/atom_vec_electron.h index fabb03438d..9175ca52f7 100644 --- a/src/USER-EFF/atom_vec_electron.h +++ b/src/USER-EFF/atom_vec_electron.h @@ -27,11 +27,17 @@ namespace LAMMPS_NS { class AtomVecElectron : public AtomVec { public: AtomVecElectron(class LAMMPS *); + + void grow_pointers(); void force_clear(int, size_t); void create_atom_post(int); void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); + +private: + int *spin; + double *eradius,*ervel,*erforce; }; } diff --git a/src/USER-MESO/atom_vec_edpd.cpp b/src/USER-MESO/atom_vec_edpd.cpp index e06ac633ec..d08a626fad 100644 --- a/src/USER-MESO/atom_vec_edpd.cpp +++ b/src/USER-MESO/atom_vec_edpd.cpp @@ -67,6 +67,20 @@ void AtomVecEDPD::init() error->all(FLERR,"Atom style edpd requires lj units"); } +/* ---------------------------------------------------------------------- + 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 AtomVecEDPD::grow_pointers() +{ + edpd_cv = atom->edpd_cv; + edpd_temp = atom->edpd_temp; + edpd_flux = atom->edpd_flux; + vest = atom->vest; + vest_temp = atom->vest_temp; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -74,7 +88,7 @@ void AtomVecEDPD::init() void AtomVecEDPD::force_clear(int n, size_t nbytes) { - memset(&atom->edpd_flux[n],0,nbytes); + memset(&edpd_flux[n],0,nbytes); } /* ---------------------------------------------------------------------- @@ -83,9 +97,9 @@ void AtomVecEDPD::force_clear(int n, size_t nbytes) void AtomVecEDPD::create_atom_post(int ilocal) { - atom->edpd_temp[ilocal] = 1.0; - atom->edpd_cv[ilocal]= 1.0e5; - atom->vest_temp[ilocal] = atom->edpd_temp[ilocal]; + edpd_temp[ilocal] = 1.0; + edpd_cv[ilocal]= 1.0e5; + vest_temp[ilocal] = edpd_temp[ilocal]; } /* ---------------------------------------------------------------------- @@ -95,9 +109,9 @@ void AtomVecEDPD::create_atom_post(int ilocal) void AtomVecEDPD::data_atom_post(int ilocal) { - atom->edpd_flux[ilocal] = 0.0; - atom->vest[ilocal][0] = 0.0; - atom->vest[ilocal][1] = 0.0; - atom->vest[ilocal][2] = 0.0; - atom->vest_temp[ilocal] = atom->edpd_temp[ilocal]; + edpd_flux[ilocal] = 0.0; + vest[ilocal][0] = 0.0; + vest[ilocal][1] = 0.0; + vest[ilocal][2] = 0.0; + vest_temp[ilocal] = edpd_temp[ilocal]; } diff --git a/src/USER-MESO/atom_vec_edpd.h b/src/USER-MESO/atom_vec_edpd.h index bb667ae792..a69c44a035 100644 --- a/src/USER-MESO/atom_vec_edpd.h +++ b/src/USER-MESO/atom_vec_edpd.h @@ -28,9 +28,16 @@ class AtomVecEDPD : public AtomVec { public: AtomVecEDPD(class LAMMPS *); void init(); + + void grow_pointers(); void force_clear(int, size_t); void create_atom_post(int); void data_atom_post(int); + + private: + double *edpd_cv,*edpd_temp,*edpd_flux; + double **vest; + double *vest_temp; }; } diff --git a/src/USER-MESO/atom_vec_mdpd.cpp b/src/USER-MESO/atom_vec_mdpd.cpp index b87ff14c3c..0acaaf6253 100644 --- a/src/USER-MESO/atom_vec_mdpd.cpp +++ b/src/USER-MESO/atom_vec_mdpd.cpp @@ -61,6 +61,18 @@ void AtomVecMDPD::init() error->all(FLERR,"Atom style mdpd requires lj units"); } +/* ---------------------------------------------------------------------- + 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 AtomVecMDPD::grow_pointers() +{ + rho = atom->rho; + drho = atom->drho; + vest = atom->vest; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -68,7 +80,7 @@ void AtomVecMDPD::init() void AtomVecMDPD::force_clear(int n, size_t nbytes) { - memset(&atom->drho[n],0,nbytes); + memset(&drho[n],0,nbytes); } /* ---------------------------------------------------------------------- @@ -78,10 +90,10 @@ void AtomVecMDPD::force_clear(int n, size_t nbytes) void AtomVecMDPD::data_atom_post(int ilocal) { - atom->drho[ilocal] = 0.0; - atom->vest[ilocal][0] = 0.0; - atom->vest[ilocal][1] = 0.0; - atom->vest[ilocal][2] = 0.0; + drho[ilocal] = 0.0; + vest[ilocal][0] = 0.0; + vest[ilocal][1] = 0.0; + vest[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- @@ -109,14 +121,12 @@ void AtomVecMDPD::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { - double *rho = atom->rho; 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 == 1) { - double *drho = atom->drho; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = drho[i]; else buf[n] = 0.0; diff --git a/src/USER-MESO/atom_vec_mdpd.h b/src/USER-MESO/atom_vec_mdpd.h index 0eb4fff2df..55f5e9bb2d 100644 --- a/src/USER-MESO/atom_vec_mdpd.h +++ b/src/USER-MESO/atom_vec_mdpd.h @@ -28,10 +28,16 @@ class AtomVecMDPD : public AtomVec { public: AtomVecMDPD(class LAMMPS *); void init(); + + void grow_pointers(); void force_clear(int, size_t); void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); + + private: + double *rho,*drho; + double **vest; }; } diff --git a/src/USER-MESO/atom_vec_tdpd.cpp b/src/USER-MESO/atom_vec_tdpd.cpp index 5734fcf9ad..f50fe168d6 100644 --- a/src/USER-MESO/atom_vec_tdpd.cpp +++ b/src/USER-MESO/atom_vec_tdpd.cpp @@ -80,6 +80,18 @@ void AtomVecTDPD::init() error->all(FLERR,"Atom style tdpd requires lj units"); } +/* ---------------------------------------------------------------------- + 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 AtomVecTDPD::grow_pointers() +{ + cc_flux = atom->cc_flux; + vest = atom->vest; +} + + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -87,7 +99,7 @@ void AtomVecTDPD::init() void AtomVecTDPD::force_clear(int n, size_t nbytes) { - memset(&atom->cc_flux[n][0],0,cc_species*nbytes); + memset(&cc_flux[n][0],0,cc_species*nbytes); } /* ---------------------------------------------------------------------- diff --git a/src/USER-MESO/atom_vec_tdpd.h b/src/USER-MESO/atom_vec_tdpd.h index 7321859fb4..971696cc5c 100644 --- a/src/USER-MESO/atom_vec_tdpd.h +++ b/src/USER-MESO/atom_vec_tdpd.h @@ -29,10 +29,15 @@ class AtomVecTDPD : public AtomVec { AtomVecTDPD(class LAMMPS *); void process_args(int, char **); void init(); + + void grow_pointers(); void force_clear(int, size_t); void data_atom_post(int); protected: + double **cc_flux; + double **vest; + int cc_species; }; diff --git a/src/USER-SMD/atom_vec_smd.cpp b/src/USER-SMD/atom_vec_smd.cpp index 9f0ed04a09..4c8126d2cc 100644 --- a/src/USER-SMD/atom_vec_smd.cpp +++ b/src/USER-SMD/atom_vec_smd.cpp @@ -62,11 +62,11 @@ AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) // except: fields_data_atom & fields_data_vel must match data file fields_grow = (char *) - "de vfrac rmass x0 radius contact_radius molecule " - "smd_data_9 e vest smd_stress " + "e de vfrac rmass x0 radius contact_radius molecule " + "smd_data_9 vest smd_stress " "eff_plastic_strain eff_plastic_strain_rate damage"; fields_copy = (char *) - "vfrac rmass x0 radius contact_radius molecule e " + "e vfrac rmass x0 radius contact_radius molecule " "eff_plastic_strain eff_plastic_strain_rate vest " "smd_data_9 smd_stress damage"; fields_comm = (char *) "radius vfrac vest e"; @@ -101,6 +101,29 @@ AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecSMD::grow_pointers() +{ + e = atom->e; + de = atom->de; + vfrac = atom->vfrac; + rmass = atom->rmass; + x0 = atom->x0; + radius = atom->radius; + contact_radius = atom->contact_radius; + molecule = atom->molecule; + smd_data_9 = atom->smd_data_9; + vest = atom->vest; + smd_stress = atom->smd_stress; + eff_plastic_strain = atom->eff_plastic_strain; + eff_plastic_strain_rate = atom->eff_plastic_strain_rate; + damage = atom->damage; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -109,8 +132,8 @@ AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) void AtomVecSMD::force_clear(int n, size_t nbytes) { - memset(&atom->de[n],0,nbytes); - memset(&atom->f[n][0],0,3*nbytes); + memset(&de[n],0,nbytes); + memset(&f[n][0],0,3*nbytes); } /* ---------------------------------------------------------------------- @@ -119,19 +142,19 @@ void AtomVecSMD::force_clear(int n, size_t nbytes) void AtomVecSMD::create_atom_post(int ilocal) { - atom->x0[ilocal][0] = atom->x[ilocal][0]; - atom->x0[ilocal][1] = atom->x[ilocal][1]; - atom->x0[ilocal][2] = atom->x[ilocal][2]; - - atom->vfrac[ilocal] = 1.0; - atom->rmass[ilocal] = 1.0; - atom->radius[ilocal] = 0.5; - atom->contact_radius[ilocal] = 0.5; - atom->molecule[ilocal] = 1; + x0[ilocal][0] = x[ilocal][0]; + x0[ilocal][1] = x[ilocal][1]; + x0[ilocal][2] = x[ilocal][2]; + + vfrac[ilocal] = 1.0; + rmass[ilocal] = 1.0; + radius[ilocal] = 0.5; + contact_radius[ilocal] = 0.5; + molecule[ilocal] = 1; - atom->smd_data_9[ilocal][0] = 1.0; // xx - atom->smd_data_9[ilocal][4] = 1.0; // yy - atom->smd_data_9[ilocal][8] = 1.0; // zz + smd_data_9[ilocal][0] = 1.0; // xx + smd_data_9[ilocal][4] = 1.0; // yy + smd_data_9[ilocal][8] = 1.0; // zz } /* ---------------------------------------------------------------------- @@ -141,32 +164,27 @@ void AtomVecSMD::create_atom_post(int ilocal) void AtomVecSMD::data_atom_post(int ilocal) { - atom->e[ilocal] = 0.0; - atom->x0[ilocal][0] = atom->x[ilocal][0]; - atom->x0[ilocal][1] = atom->x[ilocal][1]; - atom->x0[ilocal][2] = atom->x[ilocal][2]; + e[ilocal] = 0.0; + x0[ilocal][0] = x[ilocal][0]; + x0[ilocal][1] = x[ilocal][1]; + x0[ilocal][2] = x[ilocal][2]; - atom->vest[ilocal][0] = 0.0; - atom->vest[ilocal][1] = 0.0; - atom->vest[ilocal][2] = 0.0; + vest[ilocal][0] = 0.0; + vest[ilocal][1] = 0.0; + vest[ilocal][2] = 0.0; - atom->damage[ilocal] = 0.0; + damage[ilocal] = 0.0; - atom->eff_plastic_strain[ilocal] = 0.0; - atom->eff_plastic_strain_rate[ilocal] = 0.0; + eff_plastic_strain[ilocal] = 0.0; + eff_plastic_strain_rate[ilocal] = 0.0; for (int k = 0; k < NMAT_FULL; k++) - atom->smd_data_9[ilocal][k] = 0.0; + smd_data_9[ilocal][k] = 0.0; for (int k = 0; k < NMAT_SYMM; k++) - atom->smd_stress[ilocal][k] = 0.0; + smd_stress[ilocal][k] = 0.0; - atom->smd_data_9[ilocal][0] = 1.0; // xx - atom->smd_data_9[ilocal][4] = 1.0; // yy - atom->smd_data_9[ilocal][8] = 1.0; // zz + smd_data_9[ilocal][0] = 1.0; // xx + smd_data_9[ilocal][4] = 1.0; // yy + smd_data_9[ilocal][8] = 1.0; // zz } - - - - - diff --git a/src/USER-SMD/atom_vec_smd.h b/src/USER-SMD/atom_vec_smd.h index 539f209ca7..00709aeada 100644 --- a/src/USER-SMD/atom_vec_smd.h +++ b/src/USER-SMD/atom_vec_smd.h @@ -38,9 +38,17 @@ namespace LAMMPS_NS { class AtomVecSMD : public AtomVec { public: AtomVecSMD(class LAMMPS *); + + void grow_pointers(); void force_clear(int, size_t); void create_atom_post(int); void data_atom_post(int); + + private: + int *molecule; + double *e,*de,*vfrac,*rmass,*radius,*contact_radius; + double *eff_plastic_strain,*eff_plastic_strain_rate,*damage; + double **x0,**smd_data_9,**smd_stress,**vest; }; } diff --git a/src/USER-SPH/atom_vec_meso.cpp b/src/USER-SPH/atom_vec_meso.cpp index a80ab91d2e..fdddd15f27 100644 --- a/src/USER-SPH/atom_vec_meso.cpp +++ b/src/USER-SPH/atom_vec_meso.cpp @@ -52,6 +52,21 @@ AtomVecMeso::AtomVecMeso(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecMeso::grow_pointers() +{ + rho = atom->rho; + drho = atom->drho; + e = atom->e; + de = atom->de; + cv = atom->cv; + vest = atom->vest; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -59,8 +74,8 @@ AtomVecMeso::AtomVecMeso(LAMMPS *lmp) : AtomVec(lmp) void AtomVecMeso::force_clear(int n, size_t nbytes) { - memset(&atom->de[n],0,nbytes); - memset(&atom->drho[n],0,nbytes); + memset(&de[n],0,nbytes); + memset(&drho[n],0,nbytes); } /* ---------------------------------------------------------------------- @@ -69,7 +84,7 @@ void AtomVecMeso::force_clear(int n, size_t nbytes) void AtomVecMeso::create_atom_post(int ilocal) { - atom->cv[ilocal] = 1.0; + cv[ilocal] = 1.0; } /* ---------------------------------------------------------------------- @@ -79,11 +94,11 @@ void AtomVecMeso::create_atom_post(int ilocal) void AtomVecMeso::data_atom_post(int ilocal) { - atom->vest[ilocal][0] = 0.0; - atom->vest[ilocal][1] = 0.0; - atom->vest[ilocal][2] = 0.0; - atom->de[ilocal] = 0.0; - atom->drho[ilocal] = 0.0; + vest[ilocal][0] = 0.0; + vest[ilocal][1] = 0.0; + vest[ilocal][2] = 0.0; + de[ilocal] = 0.0; + drho[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -114,35 +129,30 @@ void AtomVecMeso::pack_property_atom(int index, double *buf, int n = 0; if (index == 0) { - double *rho = atom->rho; 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 == 1) { - double *drho = atom->drho; 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 == 2) { - double *e = atom->e; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = e[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 3) { - double *de = atom->de; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = de[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 4) { - double *cv = atom->cv; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = cv[i]; else buf[n] = 0.0; diff --git a/src/USER-SPH/atom_vec_meso.h b/src/USER-SPH/atom_vec_meso.h index c8a1090474..bd84c34fbc 100644 --- a/src/USER-SPH/atom_vec_meso.h +++ b/src/USER-SPH/atom_vec_meso.h @@ -27,11 +27,17 @@ namespace LAMMPS_NS { class AtomVecMeso : public AtomVec { public: AtomVecMeso(class LAMMPS *); + + void grow_pointers(); void force_clear(int, size_t); void create_atom_post(int); void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); + + private: + double *rho,*drho,*e,*de,*cv; + double **vest; }; } diff --git a/src/atom.cpp b/src/atom.cpp index 0fbee8f583..353ed510a4 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -175,42 +175,8 @@ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) iname = dname = NULL; // initialize atom style and array existence flags - // customize by adding new flag - sphere_flag = peri_flag = electron_flag = 0; - wavepacket_flag = sph_flag = 0; - - molecule_flag = 0; - q_flag = mu_flag = 0; - omega_flag = torque_flag = angmom_flag = 0; - radius_flag = rmass_flag = 0; - ellipsoid_flag = line_flag = tri_flag = body_flag = 0; - - // magnetic flags - - sp_flag = 0; - - vfrac_flag = 0; - spin_flag = eradius_flag = ervel_flag = erforce_flag = ervelforce_flag = 0; - cs_flag = csforce_flag = vforce_flag = etag_flag = 0; - - rho_flag = e_flag = cv_flag = vest_flag = 0; - dpd_flag = edpd_flag = tdpd_flag = 0; - - // USER-SMD - - smd_flag = 0; - contact_radius_flag = 0; - smd_data_9_flag = 0; - smd_stress_flag = 0; - x0_flag = 0; - eff_plastic_strain_flag = 0; - eff_plastic_strain_rate_flag = 0; - damage_flag = 0; - - // Peridynamic scale factor - - pdscale = 1.0; + set_atomflag_defaults(); // initialize peratom data structure @@ -668,6 +634,32 @@ void Atom::add_peratom_vary(const char *name, void *address, nperatom++; } +/* ---------------------------------------------------------------------- + add info for a single per-atom array to PerAtom data struct + customize by adding new flag, identical list as atom.h 2nd customization +------------------------------------------------------------------------- */ + +void Atom::set_atomflag_defaults() +{ + sphere_flag = ellipsoid_flag = line_flag = tri_flag = body_flag = 0; + peri_flag = electron_flag = 0; + wavepacket_flag = sph_flag = 0; + molecule_flag = molindex_flag = molatom_flag = 0; + q_flag = mu_flag = 0; + 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; + rho_flag = e_flag = cv_flag = vest_flag = 0; + dpd_flag = edpd_flag = tdpd_flag = 0; + sp_flag = 0; + x0_flag = 0; + smd_flag = damage_flag = 0; + contact_radius_flag = smd_data_9_flag = smd_stress_flag = 0; + eff_plastic_strain_flag = eff_plastic_strain_rate_flag = 0; + + pdscale = 1.0; +} + /* ---------------------------------------------------------------------- create an AtomVec style called from lammps.cpp, input script, restart file, replicate @@ -682,26 +674,8 @@ void Atom::create_avec(const char *style, int narg, char **arg, int trysuffix) // unset atom style and array existence flags // may have been set by old avec - // customize by adding new flag - sphere_flag = peri_flag = electron_flag = 0; - wavepacket_flag = sph_flag = 0; - - molecule_flag = 0; - q_flag = mu_flag = 0; - omega_flag = torque_flag = angmom_flag = 0; - radius_flag = rmass_flag = 0; - ellipsoid_flag = line_flag = tri_flag = body_flag = 0; - - // magnetic flags - - sp_flag = 0; - - vfrac_flag = 0; - spin_flag = eradius_flag = ervel_flag = erforce_flag = ervelforce_flag = 0; - cs_flag = csforce_flag = vforce_flag = etag_flag = 0; - - rho_flag = e_flag = cv_flag = vest_flag = 0; + set_atomflag_defaults(); // create instance of AtomVec // use grow() to initialize atom-based arrays to length 1 @@ -785,6 +759,7 @@ AtomVec *Atom::avec_creator(LAMMPS *lmp) return new T(lmp); } + /* ---------------------------------------------------------------------- */ void Atom::init() diff --git a/src/atom.h b/src/atom.h index bc1eb1a7d7..6c7110b5be 100644 --- a/src/atom.h +++ b/src/atom.h @@ -143,7 +143,8 @@ class Atom : protected Pointers { double **vest; // -------------------------------------------------------------------- - // 1st customization section: customize by adding new flags + // 2nd customization section: customize by adding new flags + // identical list as Atom::set_atomflag_defaults() // most are existence flags for per-atom vectors and arrays // 1 if variable is used, 0 if not @@ -165,14 +166,10 @@ class Atom : protected Pointers { // USER-SMD package - int smd_flag; - int contact_radius_flag; - int smd_data_9_flag; - int smd_stress_flag; int x0_flag; - int eff_plastic_strain_flag; - int eff_plastic_strain_rate_flag; - int damage_flag; + int smd_flag,damage_flag; + int contact_radius_flag,smd_data_9_flag,smd_stress_flag; + int eff_plastic_strain_flag,eff_plastic_strain_rate_flag; // Peridynamics scale factor, used by dump cfg @@ -264,6 +261,7 @@ class Atom : protected Pointers { void *, int collength=0); void create_avec(const char *, int, char **, int); virtual class AtomVec *new_avec(const char *, int, int &); + void init(); void setup(); @@ -380,6 +378,7 @@ class Atom : protected Pointers { double bininvx,bininvy,bininvz; // inverse actual bin sizes double bboxlo[3],bboxhi[3]; // bounding box of my sub-domain + void set_atomflag_defaults(); void setup_sort_bins(); int next_prime(int); diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index e31c235760..fac4cc2f6e 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -185,7 +185,7 @@ void AtomVec::grow(int n) atom->nmax = nmax; if (nmax < 0 || nmax > MAXSMALLINT) error->one(FLERR,"Per-processor system is too big"); - + tag = memory->grow(atom->tag,nmax,"atom:tag"); type = memory->grow(atom->type,nmax,"atom:type"); mask = memory->grow(atom->mask,nmax,"atom:mask"); @@ -230,6 +230,8 @@ void AtomVec::grow(int n) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); + + grow_pointers(); } /* ---------------------------------------------------------------------- @@ -2387,7 +2389,6 @@ void AtomVec::setup_fields() // set style-specific sizes // NOTE: check for others vars in atom_vec.cpp/h ?? - // NOTE: need to set maxexchange, e.g for style hybrid? comm_x_only = 1; if (ncomm) comm_x_only = 0; @@ -2435,7 +2436,6 @@ void AtomVec::setup_fields() else size_data_atom += cols; } - size_data_vel = 0; for (n = 0; n < ndata_vel; n++) { cols = mdata_vel.cols[n]; diff --git a/src/atom_vec.h b/src/atom_vec.h index 5911c8414b..94517f80ad 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -74,7 +74,8 @@ class AtomVec : protected Pointers { virtual void force_clear(int, size_t) {} - virtual void grow(int); + void grow(int); + virtual void grow_pointers() {} void copy(int, int, int); virtual void copy_bonus(int, int, int) {} diff --git a/src/atom_vec_body.cpp b/src/atom_vec_body.cpp index a04f23a47c..0f3557596f 100644 --- a/src/atom_vec_body.cpp +++ b/src/atom_vec_body.cpp @@ -100,6 +100,7 @@ AtomVecBody::~AtomVecBody() void AtomVecBody::process_args(int narg, char **arg) { // suppress unused parameter warning dependent on style_body.h + (void)(arg); if (narg < 1) error->all(FLERR,"Invalid atom_style body command"); @@ -120,11 +121,12 @@ void AtomVecBody::process_args(int narg, char **arg) icp = bptr->icp; dcp = bptr->dcp; - // max size of forward/border comm + // max size of forward/border and exchange comm // bptr values = max number of additional ivalues/dvalues from Body class size_forward_bonus += bptr->size_forward; size_border_bonus += bptr->size_border; + maxexchange = bptr->maxexchange; setup_fields(); } @@ -138,7 +140,11 @@ void AtomVecBody::process_args(int narg, char **arg) void AtomVecBody::grow(int n) { AtomVec::grow(n); + body = atom->body; + rmass = atom->rmass; + radius = atom->radius; + angmom = atom->angmom; } /* ---------------------------------------------------------------------- @@ -186,7 +192,7 @@ void AtomVecBody::copy_bonus(int i, int j, int delflag) void AtomVecBody::copy_bonus_all(int i, int j) { - atom->body[bonus[i].ilocal] = j; + body[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -503,9 +509,9 @@ int AtomVecBody::unpack_restart_bonus(int ilocal, double *buf) void AtomVecBody::create_atom_post(int ilocal) { - atom->radius[ilocal] = 0.5; - atom->rmass[ilocal] = 1.0; - atom->body[ilocal] = -1; + radius[ilocal] = 0.5; + rmass[ilocal] = 1.0; + body[ilocal] = -1; } /* ---------------------------------------------------------------------- @@ -515,19 +521,19 @@ void AtomVecBody::create_atom_post(int ilocal) void AtomVecBody::data_atom_post(int ilocal) { - body_flag = atom->body[ilocal]; + body_flag = body[ilocal]; if (body_flag == 0) body_flag = -1; else if (body_flag == 1) body_flag = 0; else error->one(FLERR,"Invalid body flag in Atoms section of data file"); - atom->body[ilocal] = body_flag; + body[ilocal] = body_flag; - if (atom->rmass[ilocal] <= 0.0) + if (rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); - atom->radius[ilocal] = 0.5; - atom->angmom[ilocal][0] = 0.0; - atom->angmom[ilocal][1] = 0.0; - atom->angmom[ilocal][2] = 0.0; + radius[ilocal] = 0.5; + angmom[ilocal][0] = 0.0; + angmom[ilocal][1] = 0.0; + angmom[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- @@ -537,12 +543,12 @@ void AtomVecBody::data_atom_post(int ilocal) void AtomVecBody::data_body(int m, int ninteger, int ndouble, int *ivalues, double *dvalues) { - if (atom->body[m]) + if (body[m]) error->one(FLERR,"Assigning body parameters to non-body atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); bonus[nlocal_bonus].ilocal = m; bptr->data_body(nlocal_bonus,ninteger,ndouble,ivalues,dvalues); - atom->body[m] = nlocal_bonus++; + body[m] = nlocal_bonus++; } /* ---------------------------------------------------------------------- @@ -570,10 +576,10 @@ bigint AtomVecBody::memory_usage_bonus() void AtomVecBody::pack_data_pre(int ilocal) { - body_flag = atom->body[ilocal]; + body_flag = body[ilocal]; - if (body_flag < 0) atom->body[ilocal] = 0; - else atom->body[ilocal] = 1; + if (body_flag < 0) body[ilocal] = 0; + else body[ilocal] = 1; } /* ---------------------------------------------------------------------- @@ -582,7 +588,7 @@ void AtomVecBody::pack_data_pre(int ilocal) void AtomVecBody::pack_data_post(int ilocal) { - atom->body[ilocal] = body_flag; + body[ilocal] = body_flag; } /* ---------------------------------------------------------------------- @@ -602,8 +608,8 @@ double AtomVecBody::radius_body(int ninteger, int ndouble, void AtomVecBody::set_quat(int m, double *quat_external) { - if (atom->body[m] < 0) error->one(FLERR,"Assigning quat to non-body atom"); - double *quat = bonus[atom->body[m]].quat; + if (body[m] < 0) error->one(FLERR,"Assigning quat to non-body atom"); + double *quat = bonus[body[m]].quat; quat[0] = quat_external[0]; quat[1] = quat_external[1]; quat[2] = quat_external[2]; quat[3] = quat_external[3]; } @@ -616,15 +622,15 @@ void AtomVecBody::set_quat(int m, double *quat_external) void AtomVecBody::check(int flag) { for (int i = 0; i < atom->nlocal; i++) { - if (atom->body[i] >= 0 && atom->body[i] >= nlocal_bonus) { + if (body[i] >= 0 && body[i] >= nlocal_bonus) { printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag); errorx->one(FLERR,"BAD AAA"); } } for (int i = atom->nlocal; i < atom->nlocal+atom->nghost; i++) { - if (atom->body[i] >= 0 && - (atom->body[i] < nlocal_bonus || - atom->body[i] >= nlocal_bonus+nghost_bonus)) { + if (body[i] >= 0 && + (body[i] < nlocal_bonus || + body[i] >= nlocal_bonus+nghost_bonus)) { printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag); errorx->one(FLERR,"BAD BBB"); } @@ -636,7 +642,7 @@ void AtomVecBody::check(int flag) } } for (int i = 0; i < nlocal_bonus; i++) { - if (atom->body[bonus[i].ilocal] != i) { + if (body[bonus[i].ilocal] != i) { printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag); errorx->one(FLERR,"BAD DDD"); } @@ -649,7 +655,7 @@ void AtomVecBody::check(int flag) } } for (int i = nlocal_bonus; i < nlocal_bonus+nghost_bonus; i++) { - if (atom->body[bonus[i].ilocal] != i) { + if (body[bonus[i].ilocal] != i) { printf("Proc %d, step %ld, flag %d\n",comm->me,update->ntimestep,flag); errorx->one(FLERR,"BAD FFF"); } diff --git a/src/atom_vec_body.h b/src/atom_vec_body.h index 3f32c8223c..adfc7768eb 100644 --- a/src/atom_vec_body.h +++ b/src/atom_vec_body.h @@ -71,12 +71,14 @@ class AtomVecBody : public AtomVec { int nlocal_bonus; private: + int *body; + double *rmass,*radius; + double **angmom; + int nghost_bonus,nmax_bonus; int intdoubleratio; // sizeof(double) / sizeof(int) int body_flag; - int *body; - MyPoolChunk *icp; MyPoolChunk *dcp; diff --git a/src/atom_vec_ellipsoid.cpp b/src/atom_vec_ellipsoid.cpp index e8ab6d5613..2537fe2538 100644 --- a/src/atom_vec_ellipsoid.cpp +++ b/src/atom_vec_ellipsoid.cpp @@ -75,6 +75,17 @@ AtomVecEllipsoid::~AtomVecEllipsoid() memory->sfree(bonus); } +/* ---------------------------------------------------------------------- + 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 AtomVecEllipsoid::grow_pointers() +{ + ellipsoid = atom->ellipsoid; + rmass = atom->rmass; +} + /* ---------------------------------------------------------------------- grow bonus data structure ------------------------------------------------------------------------- */ @@ -95,8 +106,6 @@ void AtomVecEllipsoid::grow_bonus() void AtomVecEllipsoid::copy_bonus(int i, int j, int delflag) { - int *ellipsoid = atom->ellipsoid; - // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && ellipsoid[j] >= 0) { @@ -118,7 +127,7 @@ void AtomVecEllipsoid::copy_bonus(int i, int j, int delflag) void AtomVecEllipsoid::copy_bonus_all(int i, int j) { - atom->ellipsoid[bonus[i].ilocal] = j; + ellipsoid[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -143,8 +152,6 @@ int AtomVecEllipsoid::pack_comm_bonus(int n, int *list, double *buf) int i,j,m; double *quat; - int *ellipsoid = atom->ellipsoid; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -167,8 +174,6 @@ void AtomVecEllipsoid::unpack_comm_bonus(int n, int first, double *buf) int i,m,last; double *quat; - int *ellipsoid = atom->ellipsoid; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -190,8 +195,6 @@ int AtomVecEllipsoid::pack_border_bonus(int n, int *list, double *buf) double dx,dy,dz; double *shape,*quat; - int *ellipsoid = atom->ellipsoid; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -220,8 +223,6 @@ int AtomVecEllipsoid::unpack_border_bonus(int n, int first, double *buf) int i,j,m,last; double *shape,*quat; - int *ellipsoid = atom->ellipsoid; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -257,8 +258,6 @@ int AtomVecEllipsoid::pack_exchange_bonus(int i, double *buf) { int m = 0; - int *ellipsoid = atom->ellipsoid; - if (ellipsoid[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -283,8 +282,6 @@ int AtomVecEllipsoid::unpack_exchange_bonus(int ilocal, double *buf) { int m = 0; - int *ellipsoid = atom->ellipsoid; - ellipsoid[ilocal] = (int) ubuf(buf[m++]).i; if (ellipsoid[ilocal] == 0) ellipsoid[ilocal] = -1; else { @@ -314,8 +311,6 @@ int AtomVecEllipsoid::size_restart_bonus() { int i; - int *ellipsoid = atom->ellipsoid; - int n = 0; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { @@ -336,8 +331,6 @@ int AtomVecEllipsoid::pack_restart_bonus(int i, double *buf) { int m = 0; - int *ellipsoid = atom->ellipsoid; - if (ellipsoid[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -362,8 +355,6 @@ int AtomVecEllipsoid::unpack_restart_bonus(int ilocal, double *buf) { int m = 0; - int *ellipsoid = atom->ellipsoid; - ellipsoid[ilocal] = (int) ubuf(buf[m++]).i; if (ellipsoid[ilocal] == 0) ellipsoid[ilocal] = -1; else { @@ -390,8 +381,6 @@ int AtomVecEllipsoid::unpack_restart_bonus(int ilocal, double *buf) void AtomVecEllipsoid::data_atom_bonus(int m, char **values) { - int *ellipsoid = atom->ellipsoid; - if (ellipsoid[m]) error->one(FLERR,"Assigning ellipsoid parameters to non-ellipsoid atom"); @@ -414,7 +403,7 @@ void AtomVecEllipsoid::data_atom_bonus(int m, char **values) // reset ellipsoid mass // previously stored density in rmass - atom->rmass[m] *= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; + rmass[m] *= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; bonus[nlocal_bonus].ilocal = m; ellipsoid[m] = nlocal_bonus++; @@ -437,8 +426,8 @@ bigint AtomVecEllipsoid::memory_usage_bonus() void AtomVecEllipsoid::create_atom_post(int ilocal) { - atom->rmass[ilocal] = 1.0; - atom->ellipsoid[ilocal] = -1; + rmass[ilocal] = 1.0; + ellipsoid[ilocal] = -1; } /* ---------------------------------------------------------------------- @@ -448,13 +437,13 @@ void AtomVecEllipsoid::create_atom_post(int ilocal) void AtomVecEllipsoid::data_atom_post(int ilocal) { - ellipsoid_flag = atom->ellipsoid[ilocal]; + ellipsoid_flag = ellipsoid[ilocal]; if (ellipsoid_flag == 0) ellipsoid_flag = -1; else if (ellipsoid_flag == 1) ellipsoid_flag = 0; else error->one(FLERR,"Invalid ellipsoid flag in Atoms section of data file"); - atom->ellipsoid[ilocal] = ellipsoid_flag; + ellipsoid[ilocal] = ellipsoid_flag; - if (atom->rmass[ilocal] <= 0.0) + if (rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); } @@ -467,14 +456,14 @@ void AtomVecEllipsoid::pack_data_pre(int ilocal) double *shape; ellipsoid_flag = atom->ellipsoid[ilocal]; - rmass = atom->rmass[ilocal]; + rmass_one = atom->rmass[ilocal]; - if (ellipsoid_flag < 0) atom->ellipsoid[ilocal] = 0; - else atom->ellipsoid[ilocal] = 1; + if (ellipsoid_flag < 0) ellipsoid[ilocal] = 0; + else ellipsoid[ilocal] = 1; if (ellipsoid_flag >= 0) { shape = bonus[ellipsoid_flag].shape; - atom->rmass[ilocal] /= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; + rmass[ilocal] /= 4.0*MY_PI/3.0 * shape[0]*shape[1]*shape[2]; } } @@ -484,8 +473,8 @@ void AtomVecEllipsoid::pack_data_pre(int ilocal) void AtomVecEllipsoid::pack_data_post(int ilocal) { - atom->ellipsoid[ilocal] = ellipsoid_flag; - atom->rmass[ilocal] = rmass; + ellipsoid[ilocal] = ellipsoid_flag; + rmass[ilocal] = rmass_one; } /* ---------------------------------------------------------------------- @@ -497,8 +486,6 @@ void AtomVecEllipsoid::pack_data_post(int ilocal) void AtomVecEllipsoid:: set_shape(int i, double shapex, double shapey, double shapez) { - int *ellipsoid = atom->ellipsoid; - if (ellipsoid[i] < 0) { if (shapex == 0.0 && shapey == 0.0 && shapez == 0.0) return; if (nlocal_bonus == nmax_bonus) grow_bonus(); diff --git a/src/atom_vec_ellipsoid.h b/src/atom_vec_ellipsoid.h index 79d17a2206..bbf3922bb3 100644 --- a/src/atom_vec_ellipsoid.h +++ b/src/atom_vec_ellipsoid.h @@ -36,6 +36,7 @@ class AtomVecEllipsoid : public AtomVec { AtomVecEllipsoid(class LAMMPS *); ~AtomVecEllipsoid(); + void grow_pointers(); void copy_bonus(int, int, int); void clear_bonus(); int pack_comm_bonus(int, int *, double *); @@ -62,9 +63,12 @@ class AtomVecEllipsoid : public AtomVec { int nlocal_bonus; private: + int *ellipsoid; + double *rmass; + int nghost_bonus,nmax_bonus; int ellipsoid_flag; - double rmass; + double rmass_one; void grow_bonus(); void copy_bonus_all(int, int); diff --git a/src/atom_vec_hybrid.cpp b/src/atom_vec_hybrid.cpp index 9a79f66972..d1166e5a8e 100644 --- a/src/atom_vec_hybrid.cpp +++ b/src/atom_vec_hybrid.cpp @@ -36,7 +36,6 @@ AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp) : AtomVec(lmp) // NOTE: set bonus_flag if any substyle does // set nstyles_bonus, styles_bonus - // NOTE: call method in each sub-style to set q_flag ?? // these strings will be concatenated from sub-style strings // fields_data_atom & fields_data_vel start with fields common to all styles @@ -124,8 +123,8 @@ void AtomVecHybrid::process_args(int narg, char **arg) for (int k = 0; k < nstyles; k++) { if ((styles[k]->molecular == 1 && molecular == 2) || (styles[k]->molecular == 2 && molecular == 1)) - error->all(FLERR,"Cannot mix molecular and molecule template " - "atom styles"); + error->all(FLERR, + "Cannot mix molecular and molecule template atom styles"); molecular = MAX(molecular,styles[k]->molecular); bonds_allow = MAX(bonds_allow,styles[k]->bonds_allow); @@ -135,11 +134,9 @@ void AtomVecHybrid::process_args(int narg, char **arg) mass_type = MAX(mass_type,styles[k]->mass_type); dipole_type = MAX(dipole_type,styles[k]->dipole_type); forceclearflag = MAX(forceclearflag,styles[k]->forceclearflag); + maxexchange += styles[k]->maxexchange; if (styles[k]->molecular == 2) onemols = styles[k]->onemols; - - // NOTE: need to sum this one? - maxexchange += styles[k]->maxexchange; } // issue a warning if both per-type mass and per-atom rmass are defined @@ -237,6 +234,13 @@ void AtomVecHybrid::init() /* ---------------------------------------------------------------------- */ +void AtomVecHybrid::grow_pointers() +{ + for (int k = 0; k < nstyles; k++) styles[k]->grow_pointers(); +} + +/* ---------------------------------------------------------------------- */ + void AtomVecHybrid::force_clear(int n, size_t nbytes) { for (int k = 0; k < nstyles; k++) diff --git a/src/atom_vec_hybrid.h b/src/atom_vec_hybrid.h index 7d838b7a7f..7d8e45c579 100644 --- a/src/atom_vec_hybrid.h +++ b/src/atom_vec_hybrid.h @@ -34,8 +34,9 @@ class AtomVecHybrid : public AtomVec { ~AtomVecHybrid(); void process_args(int, char **); void init(); - void force_clear(int, size_t); + void grow_pointers(); + void force_clear(int, size_t); void copy_bonus(int, int, int); void clear_bonus() {} int pack_comm_bonus(int, int *, double *); diff --git a/src/atom_vec_line.cpp b/src/atom_vec_line.cpp index 7ab697b349..e178d1f78a 100644 --- a/src/atom_vec_line.cpp +++ b/src/atom_vec_line.cpp @@ -86,6 +86,19 @@ void AtomVecLine::init() error->all(FLERR,"Atom_style line can only be used in 2d simulations"); } +/* ---------------------------------------------------------------------- + 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 AtomVecLine::grow_pointers() +{ + line = atom->line; + radius = atom->radius; + rmass = atom->rmass; + omega = atom->omega; +} + /* ---------------------------------------------------------------------- grow bonus data structure ------------------------------------------------------------------------- */ @@ -106,8 +119,6 @@ void AtomVecLine::grow_bonus() void AtomVecLine::copy_bonus(int i, int j, int delflag) { - int *line = atom->line; - // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && line[j] >= 0) { @@ -129,7 +140,7 @@ void AtomVecLine::copy_bonus(int i, int j, int delflag) void AtomVecLine::copy_bonus_all(int i, int j) { - atom->line[bonus[i].ilocal] = j; + line[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -153,8 +164,6 @@ int AtomVecLine::pack_comm_bonus(int n, int *list, double *buf) { int i,j,m; - int *line = atom->line; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -170,8 +179,6 @@ void AtomVecLine::unpack_comm_bonus(int n, int first, double *buf) { int i,m,last; - int *line = atom->line; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -185,8 +192,6 @@ int AtomVecLine::pack_border_bonus(int n, int *list, double *buf) { int i,j,m; - int *line = atom->line; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -207,8 +212,6 @@ int AtomVecLine::unpack_border_bonus(int n, int first, double *buf) { int i,j,m,last; - int *line = atom->line; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -237,8 +240,6 @@ int AtomVecLine::pack_exchange_bonus(int i, double *buf) { int m = 0; - int *line = atom->line; - if (line[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -256,8 +257,6 @@ int AtomVecLine::unpack_exchange_bonus(int ilocal, double *buf) { int m = 0; - int *line = atom->line; - line[ilocal] = (int) ubuf(buf[m++]).i; if (line[ilocal] == 0) line[ilocal] = -1; else { @@ -280,8 +279,6 @@ int AtomVecLine::size_restart_bonus() { int i; - int *line = atom->line; - int n = 0; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { @@ -302,8 +299,6 @@ int AtomVecLine::pack_restart_bonus(int i, double *buf) { int m = 0; - int *line = atom->line; - if (line[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -323,8 +318,6 @@ int AtomVecLine::unpack_restart_bonus(int ilocal, double *buf) { int m = 0; - int *line = atom->line; - line[ilocal] = (int) ubuf(buf[m++]).i; if (line[ilocal] == 0) line[ilocal] = -1; else { @@ -344,8 +337,6 @@ int AtomVecLine::unpack_restart_bonus(int ilocal, double *buf) void AtomVecLine::data_atom_bonus(int m, char **values) { - int *line = atom->line; - if (line[m]) error->one(FLERR,"Assigning line parameters to non-line atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); @@ -377,8 +368,8 @@ void AtomVecLine::data_atom_bonus(int m, char **values) // reset line radius and mass // rmass currently holds density - atom->radius[m] = 0.5 * length; - atom->rmass[m] *= length; + radius[m] = 0.5 * length; + rmass[m] *= length; bonus[nlocal_bonus].ilocal = m; line[m] = nlocal_bonus++; @@ -402,10 +393,10 @@ bigint AtomVecLine::memory_usage_bonus() void AtomVecLine::create_atom_post(int ilocal) { - double radius = 0.5; - atom->radius[ilocal] = radius; - atom->rmass[ilocal] = 4.0*MY_PI/3.0 * radius*radius*radius; - atom->line[ilocal] = -1; + double radius_one = 0.5; + radius[ilocal] = radius_one; + rmass[ilocal] = 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; + line[ilocal] = -1; } /* ---------------------------------------------------------------------- @@ -415,24 +406,24 @@ void AtomVecLine::create_atom_post(int ilocal) void AtomVecLine::data_atom_post(int ilocal) { - line_flag = atom->line[ilocal]; + line_flag = line[ilocal]; if (line_flag == 0) line_flag = -1; else if (line_flag == 1) line_flag = 0; else error->one(FLERR,"Invalid line flag in Atoms section of data file"); - atom->line[ilocal] = line_flag; + line[ilocal] = line_flag; - if (atom->rmass[ilocal] <= 0.0) + if (rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); if (line_flag < 0) { - double radius = 0.5; - atom->radius[ilocal] = radius; - atom->rmass[ilocal] *= 4.0*MY_PI/3.0 * radius*radius*radius; - } else atom->radius[ilocal] = 0.0; - - atom->omega[ilocal][0] = 0.0; - atom->omega[ilocal][1] = 0.0; - atom->omega[ilocal][2] = 0.0; + double radius_one = 0.5; + radius[ilocal] = radius_one; + rmass[ilocal] *= 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; + } else radius[ilocal] = 0.0; + + omega[ilocal][0] = 0.0; + omega[ilocal][1] = 0.0; + omega[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- @@ -441,16 +432,16 @@ void AtomVecLine::data_atom_post(int ilocal) void AtomVecLine::pack_data_pre(int ilocal) { - line_flag = atom->line[ilocal]; - rmass = atom->rmass[ilocal]; + line_flag = line[ilocal]; + rmass_one = rmass[ilocal]; - if (line_flag < 0) atom->line[ilocal] = 0; - else atom->line[ilocal] = 1; + if (line_flag < 0) line[ilocal] = 0; + else line[ilocal] = 1; if (line_flag < 0) { - double radius = atom->radius[ilocal]; - atom->rmass[ilocal] /= 4.0*MY_PI/3.0 * radius*radius*radius; - } else atom->rmass[ilocal] /= bonus[line_flag].length; + double radius_one = radius[ilocal]; + rmass[ilocal] /= 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; + } else rmass[ilocal] /= bonus[line_flag].length; } /* ---------------------------------------------------------------------- @@ -459,8 +450,8 @@ void AtomVecLine::pack_data_pre(int ilocal) void AtomVecLine::pack_data_post(int ilocal) { - atom->line[ilocal] = line_flag; - atom->rmass[ilocal] = rmass; + line[ilocal] = line_flag; + rmass[ilocal] = rmass_one; } /* ---------------------------------------------------------------------- @@ -471,8 +462,6 @@ void AtomVecLine::pack_data_post(int ilocal) void AtomVecLine::set_length(int i, double value) { - int *line = atom->line; - if (line[i] < 0) { if (value == 0.0) return; if (nlocal_bonus == nmax_bonus) grow_bonus(); @@ -489,8 +478,8 @@ void AtomVecLine::set_length(int i, double value) // also set radius = half of length // unless value = 0.0, then set diameter = 1.0 - atom->radius[i] = 0.5 * value; - if (value == 0.0) atom->radius[i] = 0.5; + radius[i] = 0.5 * value; + if (value == 0.0) radius[i] = 0.5; } /* ---------------------------------------------------------------------- diff --git a/src/atom_vec_line.h b/src/atom_vec_line.h index a47843f4f2..7bca58c64b 100644 --- a/src/atom_vec_line.h +++ b/src/atom_vec_line.h @@ -36,6 +36,7 @@ class AtomVecLine : public AtomVec { ~AtomVecLine(); void init(); + void grow_pointers(); void copy_bonus(int, int, int); void clear_bonus(); int pack_comm_bonus(int, int *, double *); @@ -62,9 +63,13 @@ class AtomVecLine : public AtomVec { int nlocal_bonus; private: + int *line; + double *radius,*rmass; + double **omega; + int nghost_bonus,nmax_bonus; int line_flag; - double rmass; + double rmass_one; void grow_bonus(); void copy_bonus_all(int, int); diff --git a/src/atom_vec_sphere.cpp b/src/atom_vec_sphere.cpp index b601fc8f7c..64a198c94d 100644 --- a/src/atom_vec_sphere.cpp +++ b/src/atom_vec_sphere.cpp @@ -100,14 +100,25 @@ void AtomVecSphere::init() } } +/* ---------------------------------------------------------------------- + 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 AtomVecSphere::grow_pointers() +{ + radius = atom->radius; + rmass = atom->rmass; +} + /* ---------------------------------------------------------------------- initialize non-zero atom quantities ------------------------------------------------------------------------- */ void AtomVecSphere::create_atom_post(int ilocal) { - atom->radius[ilocal] = 0.5; - atom->rmass[ilocal] = 4.0*MY_PI/3.0 * 0.5*0.5*0.5; + radius[ilocal] = 0.5; + rmass[ilocal] = 4.0*MY_PI/3.0 * 0.5*0.5*0.5; } /* ---------------------------------------------------------------------- @@ -117,13 +128,12 @@ void AtomVecSphere::create_atom_post(int ilocal) void AtomVecSphere::data_atom_post(int ilocal) { - double radius = 0.5 * atom->radius[ilocal]; - atom->radius[ilocal] = radius; - if (radius > 0.0) - atom->rmass[ilocal] = - 4.0*MY_PI/3.0 * radius*radius*radius * atom->rmass[ilocal]; + radius_one = 0.5 * atom->radius[ilocal]; + radius[ilocal] = radius_one; + if (radius_one > 0.0) + rmass[ilocal] *= 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; - if (atom->rmass[ilocal] <= 0.0) + if (rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); } @@ -132,13 +142,14 @@ void AtomVecSphere::data_atom_post(int ilocal) ------------------------------------------------------------------------- */ void AtomVecSphere::pack_data_pre(int ilocal) -{ - radius = atom->radius[ilocal]; - rmass = atom->rmass[ilocal]; +{ + radius_one = radius[ilocal]; + rmass_one = rmass[ilocal]; - atom->radius[ilocal] *= 2.0; - if (radius == 0.0) - atom->rmass[ilocal] = rmass / (4.0*MY_PI/3.0 * radius*radius*radius); + radius[ilocal] *= 2.0; + if (radius_one!= 0.0) + rmass[ilocal] = + rmass_one / (4.0*MY_PI/3.0 * radius_one*radius_one*radius_one); } /* ---------------------------------------------------------------------- @@ -146,7 +157,7 @@ void AtomVecSphere::pack_data_pre(int ilocal) ------------------------------------------------------------------------- */ void AtomVecSphere::pack_data_post(int ilocal) -{ - atom->radius[ilocal] = radius; - atom->rmass[ilocal] = rmass; +{ + radius[ilocal] = radius_one; + rmass[ilocal] = rmass_one; } diff --git a/src/atom_vec_sphere.h b/src/atom_vec_sphere.h index c205ba43de..2b735f1163 100644 --- a/src/atom_vec_sphere.h +++ b/src/atom_vec_sphere.h @@ -29,14 +29,18 @@ class AtomVecSphere : public AtomVec { AtomVecSphere(class LAMMPS *); void process_args(int, char **); void init(); + + void grow_pointers(); void create_atom_post(int); void data_atom_post(int); void pack_data_pre(int); void pack_data_post(int); private: + double *radius,*rmass; + int radvary; - double radius,rmass; + double radius_one,rmass_one; }; } diff --git a/src/atom_vec_tri.cpp b/src/atom_vec_tri.cpp index 7345646a1e..b130198075 100644 --- a/src/atom_vec_tri.cpp +++ b/src/atom_vec_tri.cpp @@ -88,6 +88,20 @@ void AtomVecTri::init() error->all(FLERR,"Atom_style tri can only be used in 3d simulations"); } +/* ---------------------------------------------------------------------- + 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 AtomVecTri::grow_pointers() +{ + tri = atom->tri; + radius = atom->radius; + rmass = atom->rmass; + omega = atom->omega; + angmom = atom->angmom; +} + /* ---------------------------------------------------------------------- grow bonus data structure ------------------------------------------------------------------------- */ @@ -109,8 +123,6 @@ void AtomVecTri::grow_bonus() void AtomVecTri::copy_bonus(int i, int j, int delflag) { - int *tri = atom->tri; - // if deleting atom J via delflag and J has bonus data, then delete it if (delflag && tri[j] >= 0) { @@ -132,7 +144,7 @@ void AtomVecTri::copy_bonus(int i, int j, int delflag) void AtomVecTri::copy_bonus_all(int i, int j) { - atom->tri[bonus[i].ilocal] = j; + tri[bonus[i].ilocal] = j; memcpy(&bonus[j],&bonus[i],sizeof(Bonus)); } @@ -157,8 +169,6 @@ int AtomVecTri::pack_comm_bonus(int n, int *list, double *buf) int i,j,m; double *quat; - int *tri = atom->tri; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -181,8 +191,6 @@ void AtomVecTri::unpack_comm_bonus(int n, int first, double *buf) int i,m,last; double *quat; - int *tri = atom->tri; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -203,8 +211,6 @@ int AtomVecTri::pack_border_bonus(int n, int *list, double *buf) int i,j,m; double *quat,*c1,*c2,*c3,*inertia; - int *tri = atom->tri; - m = 0; for (i = 0; i < n; i++) { j = list[i]; @@ -245,8 +251,6 @@ int AtomVecTri::unpack_border_bonus(int n, int first, double *buf) int i,j,m,last; double *quat,*c1,*c2,*c3,*inertia; - int *tri = atom->tri; - m = 0; last = first + n; for (i = first; i < last; i++) { @@ -294,8 +298,6 @@ int AtomVecTri::pack_exchange_bonus(int i, double *buf) { int m = 0; - int *tri = atom->tri; - if (tri[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -332,8 +334,6 @@ int AtomVecTri::unpack_exchange_bonus(int ilocal, double *buf) { int m = 0; - int *tri = atom->tri; - tri[ilocal] = (int) ubuf(buf[m++]).i; if (tri[ilocal] == 0) tri[ilocal] = -1; else { @@ -375,8 +375,6 @@ int AtomVecTri::size_restart_bonus() { int i; - int *tri = atom->tri; - int n = 0; int nlocal = atom->nlocal; for (i = 0; i < nlocal; i++) { @@ -395,8 +393,6 @@ int AtomVecTri::pack_restart_bonus(int i, double *buf) { int m = 0; - int *tri = atom->tri; - if (tri[i] < 0) buf[m++] = ubuf(0).d; else { buf[m++] = ubuf(1).d; @@ -435,8 +431,6 @@ int AtomVecTri::unpack_restart_bonus(int ilocal, double *buf) { int m = 0; - int *tri = atom->tri; - tri[ilocal] = (int) ubuf(buf[m++]).i; if (tri[ilocal] == 0) tri[ilocal] = -1; else { @@ -475,8 +469,6 @@ int AtomVecTri::unpack_restart_bonus(int ilocal, double *buf) void AtomVecTri::data_atom_bonus(int m, char **values) { - int *tri = atom->tri; - if (tri[m]) error->one(FLERR,"Assigning tri parameters to non-tri atom"); if (nlocal_bonus == nmax_bonus) grow_bonus(); @@ -523,9 +515,9 @@ void AtomVecTri::data_atom_bonus(int m, char **values) if (delta/size > EPSILON) error->one(FLERR,"Inconsistent triangle in data file"); - atom->x[m][0] = centroid[0]; - atom->x[m][1] = centroid[1]; - atom->x[m][2] = centroid[2]; + x[m][0] = centroid[0]; + x[m][1] = centroid[1]; + x[m][2] = centroid[2]; // reset tri radius and mass // rmass currently holds density @@ -533,22 +525,22 @@ void AtomVecTri::data_atom_bonus(int m, char **values) double c4[3]; MathExtra::sub3(c1,centroid,c4); - atom->radius[m] = MathExtra::lensq3(c4); + radius[m] = MathExtra::lensq3(c4); MathExtra::sub3(c2,centroid,c4); - atom->radius[m] = MAX(atom->radius[m],MathExtra::lensq3(c4)); + radius[m] = MAX(radius[m],MathExtra::lensq3(c4)); MathExtra::sub3(c3,centroid,c4); - atom->radius[m] = MAX(atom->radius[m],MathExtra::lensq3(c4)); - atom->radius[m] = sqrt(atom->radius[m]); + radius[m] = MAX(radius[m],MathExtra::lensq3(c4)); + radius[m] = sqrt(radius[m]); double norm[3]; MathExtra::cross3(c2mc1,c3mc1,norm); double area = 0.5 * MathExtra::len3(norm); - atom->rmass[m] *= area; + rmass[m] *= area; // inertia = inertia tensor of triangle as 6-vector in Voigt notation double inertia[6]; - MathExtra::inertia_triangle(c1,c2,c3,atom->rmass[m],inertia); + MathExtra::inertia_triangle(c1,c2,c3,rmass[m],inertia); // diagonalize inertia tensor via Jacobi rotations // bonus[].inertia = 3 eigenvalues = principal moments of inertia @@ -622,10 +614,10 @@ bigint AtomVecTri::memory_usage_bonus() void AtomVecTri::create_atom_post(int ilocal) { - double radius = 0.5; - atom->radius[ilocal] = radius; - atom->rmass[ilocal] = 4.0*MY_PI/3.0 * radius*radius*radius; - atom->tri[ilocal] = -1; + double radius_one = 0.5; + radius[ilocal] = radius_one; + rmass[ilocal] = 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; + tri[ilocal] = -1; } /* ---------------------------------------------------------------------- @@ -635,27 +627,27 @@ void AtomVecTri::create_atom_post(int ilocal) void AtomVecTri::data_atom_post(int ilocal) { - tri_flag = atom->tri[ilocal]; + tri_flag = tri[ilocal]; if (tri_flag == 0) tri_flag = -1; else if (tri_flag == 1) tri_flag = 0; else error->one(FLERR,"Invalid tri flag in Atoms section of data file"); - atom->tri[ilocal] = tri_flag; + tri[ilocal] = tri_flag; - if (atom->rmass[ilocal] <= 0.0) + if (rmass[ilocal] <= 0.0) error->one(FLERR,"Invalid density in Atoms section of data file"); if (tri_flag < 0) { - double radius = 0.5; - atom->radius[ilocal] = radius; - atom->rmass[ilocal] *= 4.0*MY_PI/3.0 * radius*radius*radius; - } else atom->radius[ilocal] = 0.0; - - atom->omega[ilocal][0] = 0.0; - atom->omega[ilocal][1] = 0.0; - atom->omega[ilocal][2] = 0.0; - atom->angmom[ilocal][0] = 0.0; - atom->angmom[ilocal][1] = 0.0; - atom->angmom[ilocal][2] = 0.0; + double radius_one = 0.5; + radius[ilocal] = radius_one; + rmass[ilocal] *= 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; + } else radius[ilocal] = 0.0; + + omega[ilocal][0] = 0.0; + omega[ilocal][1] = 0.0; + omega[ilocal][2] = 0.0; + angmom[ilocal][0] = 0.0; + angmom[ilocal][1] = 0.0; + angmom[ilocal][2] = 0.0; } /* ---------------------------------------------------------------------- @@ -664,22 +656,22 @@ void AtomVecTri::data_atom_post(int ilocal) void AtomVecTri::pack_data_pre(int ilocal) { - tri_flag = atom->tri[ilocal]; - rmass = atom->rmass[ilocal]; + tri_flag = tri[ilocal]; + rmass_one = rmass[ilocal]; - if (tri_flag < 0) atom->tri[ilocal] = 0; - else atom->tri[ilocal] = 1; + if (tri_flag < 0) tri[ilocal] = 0; + else tri[ilocal] = 1; if (tri_flag < 0) { - double radius = atom->radius[ilocal]; - atom->rmass[ilocal] /= 4.0*MY_PI/3.0 * radius*radius*radius; + double radius_one = radius[ilocal]; + rmass[ilocal] /= 4.0*MY_PI/3.0 * radius_one*radius_one*radius_one; } else { double c2mc1[3],c3mc1[3],norm[3]; MathExtra::sub3(bonus[tri_flag].c2,bonus[tri_flag].c1,c2mc1); MathExtra::sub3(bonus[tri_flag].c3,bonus[tri_flag].c1,c3mc1); MathExtra::cross3(c2mc1,c3mc1,norm); double area = 0.5 * MathExtra::len3(norm); - atom->rmass[ilocal] /= area; + rmass[ilocal] /= area; } } @@ -689,8 +681,8 @@ void AtomVecTri::pack_data_pre(int ilocal) void AtomVecTri::pack_data_post(int ilocal) { - atom->tri[ilocal] = tri_flag; - atom->rmass[ilocal] = rmass; + tri[ilocal] = tri_flag; + rmass[ilocal] = rmass_one; } /* ---------------------------------------------------------------------- @@ -704,8 +696,6 @@ void AtomVecTri::set_equilateral(int i, double size) // also set radius = distance from center to corner-pt = len(c1) // unless size = 0.0, then set diameter = 1.0 - int *tri = atom->tri; - if (tri[i] < 0) { if (size == 0.0) return; if (nlocal_bonus == nmax_bonus) grow_bonus(); @@ -730,11 +720,11 @@ void AtomVecTri::set_equilateral(int i, double size) inertia[0] = sqrt(3.0)/96.0 * size*size*size*size; inertia[1] = sqrt(3.0)/96.0 * size*size*size*size; inertia[2] = sqrt(3.0)/48.0 * size*size*size*size; - atom->radius[i] = MathExtra::len3(c1); + radius[i] = MathExtra::len3(c1); bonus[nlocal_bonus].ilocal = i; tri[i] = nlocal_bonus++; } else if (size == 0.0) { - atom->radius[i] = 0.5; + radius[i] = 0.5; copy_bonus_all(nlocal_bonus-1,tri[i]); nlocal_bonus--; tri[i] = -1; @@ -755,6 +745,6 @@ void AtomVecTri::set_equilateral(int i, double size) inertia[0] = sqrt(3.0)/96.0 * size*size*size*size; inertia[1] = sqrt(3.0)/96.0 * size*size*size*size; inertia[2] = sqrt(3.0)/48.0 * size*size*size*size; - atom->radius[i] = MathExtra::len3(c1); + radius[i] = MathExtra::len3(c1); } } diff --git a/src/atom_vec_tri.h b/src/atom_vec_tri.h index ad4c0103ca..0b16285fe6 100644 --- a/src/atom_vec_tri.h +++ b/src/atom_vec_tri.h @@ -38,6 +38,7 @@ class AtomVecTri : public AtomVec { ~AtomVecTri(); void init(); + void grow_pointers(); void copy_bonus(int, int, int); void clear_bonus(); int pack_comm_bonus(int, int *, double *); @@ -64,9 +65,13 @@ class AtomVecTri : public AtomVec { int nlocal_bonus; private: + int *tri; + double *radius,*rmass; + double **omega,**angmom; + int nghost_bonus,nmax_bonus; int tri_flag; - double rmass; + double rmass_one; void grow_bonus(); void copy_bonus_all(int, int); diff --git a/src/replicate.cpp b/src/replicate.cpp index 3659f7cf7a..26b61769b0 100644 --- a/src/replicate.cpp +++ b/src/replicate.cpp @@ -100,7 +100,8 @@ void Replicate::command(int narg, char **arg) maxmol = maxmol_all; } - // check image flags maximum extent; only efficient small image flags compared to new system + // check image flags maximum extent + // only efficient small image flags compared to new system int _imagelo[3], _imagehi[3]; _imagelo[0] = 0; -- GitLab From ccc8f29d60cabd9971c7db62b9db1e84b95d6aa8 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 18 Dec 2019 12:04:37 -0700 Subject: [PATCH 015/577] added support for USER-AWPMD package --- src/USER-AWPMD/atom_vec_wavepacket.cpp | 25 +++++++++++------ src/USER-AWPMD/atom_vec_wavepacket.h | 6 ++++ src/USER-AWPMD/pair_awpmd_cut.cpp | 26 +++++++++--------- src/USER-SMD/atom_vec_smd.cpp | 2 +- src/atom.cpp | 8 +++--- src/atom.h | 6 ++-- src/atom_vec.cpp | 7 ++--- src/atom_vec_body.cpp | 9 ++---- src/atom_vec_body.h | 2 +- src/atom_vec_hybrid.cpp | 38 ++++++++++++++++++++++---- src/atom_vec_hybrid.h | 3 +- 11 files changed, 86 insertions(+), 46 deletions(-) diff --git a/src/USER-AWPMD/atom_vec_wavepacket.cpp b/src/USER-AWPMD/atom_vec_wavepacket.cpp index d643ae8e0a..c71a3cb6c2 100644 --- a/src/USER-AWPMD/atom_vec_wavepacket.cpp +++ b/src/USER-AWPMD/atom_vec_wavepacket.cpp @@ -61,6 +61,20 @@ AtomVecWavepacket::AtomVecWavepacket(LAMMPS *lmp) : AtomVec(lmp) 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 AtomVecWavepacket::grow_pointers() +{ + q = atom->q; + spin = atom->spin; + eradius = atom->eradius; + ervel = atom->ervel; + erforce = atom->erforce; +} + /* ---------------------------------------------------------------------- clear extra forces starting at atom N nbytes = # of bytes to clear for a per-atom vector @@ -68,7 +82,7 @@ AtomVecWavepacket::AtomVecWavepacket(LAMMPS *lmp) : AtomVec(lmp) void AtomVecWavepacket::force_clear(int n, size_t nbytes) { - memset(&atom->erforce[n],0,nbytes); + memset(&erforce[n],0,nbytes); } /* ---------------------------------------------------------------------- @@ -78,7 +92,7 @@ void AtomVecWavepacket::force_clear(int n, size_t nbytes) void AtomVecWavepacket::create_atom_post(int ilocal) { - atom->q[ilocal] = 1.0; + q[ilocal] = 1.0; } /* ---------------------------------------------------------------------- @@ -88,7 +102,7 @@ void AtomVecWavepacket::create_atom_post(int ilocal) void AtomVecWavepacket::data_atom_post(int ilocal) { - atom->ervel[ilocal] = 0.0; + ervel[ilocal] = 0.0; } /* ---------------------------------------------------------------------- @@ -113,33 +127,28 @@ int AtomVecWavepacket::property_atom(char *name) void AtomVecWavepacket::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) { - int *spin = atom->spin; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = spin[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 1) { - double *eradius = atom->eradius; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = eradius[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 2) { - double *ervel = atom->ervel; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = ervel[i]; else buf[n] = 0.0; n += nvalues; } } else if (index == 3) { - double *erforce = atom->erforce; for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) buf[n] = erforce[i]; else buf[n] = 0.0; diff --git a/src/USER-AWPMD/atom_vec_wavepacket.h b/src/USER-AWPMD/atom_vec_wavepacket.h index e7db15db14..123414eeb7 100644 --- a/src/USER-AWPMD/atom_vec_wavepacket.h +++ b/src/USER-AWPMD/atom_vec_wavepacket.h @@ -27,11 +27,17 @@ namespace LAMMPS_NS { class AtomVecWavepacket : public AtomVec { public: AtomVecWavepacket(class LAMMPS *); + + void grow_pointers(); void force_clear(int, size_t); void create_atom_post(int); void data_atom_post(int); int property_atom(char *); void pack_property_atom(int, double *, int, int); + + private: + int *spin; + double *q,*eradius,*ervel,*erforce; }; } diff --git a/src/USER-AWPMD/pair_awpmd_cut.cpp b/src/USER-AWPMD/pair_awpmd_cut.cpp index 092327c367..e382a1cb9c 100644 --- a/src/USER-AWPMD/pair_awpmd_cut.cpp +++ b/src/USER-AWPMD/pair_awpmd_cut.cpp @@ -259,7 +259,7 @@ void PairAWPMDCut::compute(int eflag, int vflag) Vector_3 xx=Vector_3(x[i][0],x[i][1],x[i][2]); Vector_3 rv=m*Vector_3(v[i][0],v[i][1],v[i][2]); double pv=ermscale*m*atom->ervel[i]; - Vector_2 cc=Vector_2(atom->cs[2*i],atom->cs[2*i+1]); + Vector_2 cc=Vector_2(atom->cs[i][0],atom->cs[i][1]); gmap[i]=wpmd->add_split(xx,rv,atom->eradius[i],pv,cc,1.,atom->q[i],itag[i] : -atom->tag[i]); // resetting for the case constraints were applied v[i][0]=rv[0]/m; @@ -284,7 +284,7 @@ void PairAWPMDCut::compute(int eflag, int vflag) } else { // electron int iel=gmap[i]; int s=spin[i] >0 ? 0 : 1; - wpmd->get_wp_force(s,iel,(Vector_3 *)f[i],(Vector_3 *)(atom->vforce+3*i),atom->erforce+i,atom->ervelforce+i,(Vector_2 *)(atom->csforce+2*i)); + wpmd->get_wp_force(s,iel,(Vector_3 *)f[i],(Vector_3 *)(atom->vforce[i]),atom->erforce+i,atom->ervelforce+i,(Vector_2 *)(atom->csforce[i])); } } @@ -671,11 +671,11 @@ void PairAWPMDCut::min_xf_get(int /* ignore */) double *eradius = atom->eradius; double *erforce = atom->erforce; double **v=atom->v; - double *vforce=atom->vforce; + double **vforce=atom->vforce; double *ervel=atom->ervel; double *ervelforce=atom->ervelforce; - double *cs=atom->cs; - double *csforce=atom->csforce; + double **cs=atom->cs; + double **csforce=atom->csforce; int *spin = atom->spin; int nlocal = atom->nlocal; @@ -686,14 +686,14 @@ void PairAWPMDCut::min_xf_get(int /* ignore */) min_varforce[7*i] = eradius[i]*erforce[i]; for(int j=0;j<3;j++){ min_var[7*i+1+3*j] = v[i][j]; - min_varforce[7*i+1+3*j] = vforce[3*i+j]; + min_varforce[7*i+1+3*j] = vforce[i][j]; } min_var[7*i+4] = ervel[i]; min_varforce[7*i+4] = ervelforce[i]; - min_var[7*i+5] = cs[2*i]; - min_varforce[7*i+5] = csforce[2*i]; - min_var[7*i+6] = cs[2*i+1]; - min_varforce[7*i+6] = csforce[2*i+1]; + min_var[7*i+5] = cs[i][0]; + min_varforce[7*i+5] = csforce[i][0]; + min_var[7*i+6] = cs[i][1]; + min_varforce[7*i+6] = csforce[i][1]; } else { for(int j=0;j<7;j++) @@ -710,7 +710,7 @@ void PairAWPMDCut::min_x_set(int /* ignore */) double *eradius = atom->eradius; double **v=atom->v; double *ervel=atom->ervel; - double *cs=atom->cs; + double **cs=atom->cs; int *spin = atom->spin; int nlocal = atom->nlocal; @@ -721,8 +721,8 @@ void PairAWPMDCut::min_x_set(int /* ignore */) for(int j=0;j<3;j++) v[i][j]=min_var[7*i+1+3*j]; ervel[i]=min_var[7*i+4]; - cs[2*i]=min_var[7*i+5]; - cs[2*i+1]=min_var[7*i+6]; + cs[i][0]=min_var[7*i+5]; + cs[i][1]=min_var[7*i+6]; } } } diff --git a/src/USER-SMD/atom_vec_smd.cpp b/src/USER-SMD/atom_vec_smd.cpp index 4c8126d2cc..42978d67d6 100644 --- a/src/USER-SMD/atom_vec_smd.cpp +++ b/src/USER-SMD/atom_vec_smd.cpp @@ -90,7 +90,7 @@ AtomVecSMD::AtomVecSMD(LAMMPS *lmp) : AtomVec(lmp) "x0 vest vfrac rmass radius contact_radius molecule e " "eff_plastic_strain eff_plastic_strain_rate smd_data_9 smd_stress damage"; fields_data_atom = (char *) - "id type molecule vfrac rmass radius contact_radius x"; + "id type molecule vfrac rmass radius contact_radius x0 x"; fields_data_vel = (char *) "id v"; // set these array sizes based on defines diff --git a/src/atom.cpp b/src/atom.cpp index 353ed510a4..1470c873a6 100644 --- a/src/atom.cpp +++ b/src/atom.cpp @@ -134,8 +134,8 @@ Atom::Atom(LAMMPS *lmp) : Pointers(lmp) spin = NULL; eradius = ervel = erforce = NULL; - ervelforce = cs = csforce = NULL; - vforce = NULL; + ervelforce = NULL; + cs = csforce = vforce = NULL; etag = NULL; // USER-DPD package @@ -512,8 +512,8 @@ void Atom::peratom_create() // USER-AWPMD package - add_peratom("cs",&cs,DOUBLE,0); - add_peratom("csforce",&csforce,DOUBLE,0); + add_peratom("cs",&cs,DOUBLE,2); + add_peratom("csforce",&csforce,DOUBLE,2); add_peratom("vforce",&vforce,DOUBLE,3); add_peratom("ervelforce",&ervelforce,DOUBLE,0); add_peratom("etag",&etag,INT,0); diff --git a/src/atom.h b/src/atom.h index 6c7110b5be..ab1ad35f5f 100644 --- a/src/atom.h +++ b/src/atom.h @@ -109,8 +109,8 @@ class Atom : protected Pointers { int *spin; double *eradius,*ervel,*erforce; - double *ervelforce,*cs,*csforce; - double **vforce; + double *ervelforce; + double **cs,**csforce,**vforce; int *etag; // USER-DPD package @@ -322,7 +322,7 @@ class Atom : protected Pointers { inline int get_map_size() {return map_tag_max+1;}; inline int get_map_maxarray() {return map_maxarray+1;}; - // NOTE: placeholder method until AtomVec is refactored + // NOTE: placeholder method until KOKKOS/AtomVec is refactored int memcheck(const char *) {return 1;} bigint memory_usage(); diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index fac4cc2f6e..77ba68f651 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -1368,7 +1368,7 @@ int AtomVec::size_restart() int i,nn,cols,collength,ncols; void *plength; - // NOTE: need to worry about overflow of returned int ?? + // NOTE: need to worry about overflow of returned int N int nlocal = atom->nlocal; @@ -1738,9 +1738,9 @@ void AtomVec::data_atom(double *coord, imageint imagetmp, char **values) // error checks applicable to all styles - if (atom->tag[nlocal] <= 0) + if (tag[nlocal] <= 0) error->one(FLERR,"Invalid atom ID in Atoms section of data file"); - if (atom->type[nlocal] <= 0 || atom->type[nlocal] > atom->ntypes) + if (type[nlocal] <= 0 || type[nlocal] > atom->ntypes) error->one(FLERR,"Invalid atom type in Atoms section of data file"); // if needed, modify unpacked values or initialize other peratom values @@ -2388,7 +2388,6 @@ void AtomVec::setup_fields() } // set style-specific sizes - // NOTE: check for others vars in atom_vec.cpp/h ?? comm_x_only = 1; if (ncomm) comm_x_only = 0; diff --git a/src/atom_vec_body.cpp b/src/atom_vec_body.cpp index 0f3557596f..c262f1a5b6 100644 --- a/src/atom_vec_body.cpp +++ b/src/atom_vec_body.cpp @@ -132,15 +132,12 @@ void AtomVecBody::process_args(int narg, char **arg) } /* ---------------------------------------------------------------------- - grow atom arrays - must set local copy of body ptr - needed in replicate when 2 atom classes exist and pack_restart() is called + 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 AtomVecBody::grow(int n) +void AtomVecBody::grow_pointers() { - AtomVec::grow(n); - body = atom->body; rmass = atom->rmass; radius = atom->radius; diff --git a/src/atom_vec_body.h b/src/atom_vec_body.h index adfc7768eb..a47cfb3b54 100644 --- a/src/atom_vec_body.h +++ b/src/atom_vec_body.h @@ -43,7 +43,7 @@ class AtomVecBody : public AtomVec { ~AtomVecBody(); void process_args(int, char **); - void grow(int); + void grow_pointers(); void copy_bonus(int, int, int); void clear_bonus(); int pack_comm_bonus(int, int *, double *); diff --git a/src/atom_vec_hybrid.cpp b/src/atom_vec_hybrid.cpp index d1166e5a8e..965bfe8543 100644 --- a/src/atom_vec_hybrid.cpp +++ b/src/atom_vec_hybrid.cpp @@ -31,12 +31,10 @@ AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp) : AtomVec(lmp) keywords = NULL; fieldstrings = NULL; + bonus_flag = 0; nstyles_bonus = 0; styles_bonus = NULL; - // NOTE: set bonus_flag if any substyle does - // set nstyles_bonus, styles_bonus - // these strings will be concatenated from sub-style strings // fields_data_atom & fields_data_vel start with fields common to all styles @@ -45,6 +43,8 @@ AtomVecHybrid::AtomVecHybrid(LAMMPS *lmp) : AtomVec(lmp) fields_exchange = fields_restart = fields_create = (char *) ""; fields_data_atom = (char *) "id type x"; fields_data_vel = (char *) "id v"; + + fields_allocated = 0; } /* ---------------------------------------------------------------------- */ @@ -56,7 +56,10 @@ AtomVecHybrid::~AtomVecHybrid() for (int k = 0; k < nstyles; k++) delete [] keywords[k]; delete [] keywords; - // NOTE: need to check these have actually been allocated + for (int k = 0; k < nstyles_bonus; k++) delete styles_bonus[k]; + delete [] styles_bonus; + + if (!fields_allocated) return; delete [] fields_grow; delete [] fields_copy; @@ -198,6 +201,8 @@ void AtomVecHybrid::process_args(int narg, char **arg) fields_data_atom = merge_fields(10,fields_data_atom,0,null); fields_data_vel = merge_fields(11,fields_data_vel,0,null); + fields_allocated = 1; + // check concat_grow for multiple special-case fields // may cause issues with style-specific create_atom() and data_atom() methods // issue warnings if appear in multiple sub-styles @@ -219,6 +224,23 @@ void AtomVecHybrid::process_args(int narg, char **arg) delete [] concat_grow; + // set bonus_flag if any substyle has bonus data + // set nstyles_bonus & styles_bonus + + nstyles_bonus = 0; + for (int k = 0; k < nstyles; k++) + if (styles[k]->bonus_flag) nstyles_bonus++; + + if (nstyles_bonus) { + bonus_flag = 1; + styles_bonus = new AtomVec*[nstyles_bonus]; + nstyles_bonus = 0; + for (int k = 0; k < nstyles; k++) { + if (styles[k]->bonus_flag) + styles_bonus[nstyles_bonus++] = styles[k]; + } + } + // parent AtomVec can now operate on merged fields setup_fields(); @@ -326,7 +348,13 @@ void AtomVecHybrid::copy_bonus(int i, int j, int delflag) styles_bonus[k]->copy_bonus(i,j,delflag); } -// NOTE: need a clear_bonus() ? +/* ---------------------------------------------------------------------- */ + +void AtomVecHybrid::clear_bonus() +{ + for (int k = 0; k < nstyles_bonus; k++) + styles_bonus[k]->clear_bonus(); +} /* ---------------------------------------------------------------------- */ diff --git a/src/atom_vec_hybrid.h b/src/atom_vec_hybrid.h index 7d8e45c579..69b0aab7b7 100644 --- a/src/atom_vec_hybrid.h +++ b/src/atom_vec_hybrid.h @@ -38,7 +38,7 @@ class AtomVecHybrid : public AtomVec { void grow_pointers(); void force_clear(int, size_t); void copy_bonus(int, int, int); - void clear_bonus() {} + void clear_bonus(); int pack_comm_bonus(int, int *, double *); void unpack_comm_bonus(int, int, double *); int pack_border_bonus(int, int *, double *); @@ -64,6 +64,7 @@ class AtomVecHybrid : public AtomVec { private: int nallstyles; char **allstyles; + int fields_allocated; struct FieldStrings { char **fstr; -- GitLab From b3a7aa6541bffb443c1de4823ec7e26691c99bed Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Wed, 22 Jan 2020 17:48:50 -0500 Subject: [PATCH 016/577] correct whitespace issue --- src/modify.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modify.cpp b/src/modify.cpp index 732770f34e..be6624e6c1 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -960,12 +960,12 @@ void Modify::add_fix(int narg, char **arg, int trysuffix) replace it later with the desired Fix instance ------------------------------------------------------------------------- */ -void Modify::replace_fix(const char *replaceID, +void Modify::replace_fix(const char *replaceID, int narg, char **arg, int trysuffix) { int ifix = find_fix(replaceID); if (ifix < 0) error->all(FLERR,"Modify replace_fix ID could not be found"); - + // change ID, igroup, style of fix being replaced to match new fix // requires some error checking on arguments for new fix -- GitLab From 66c5fa2abd78c0de8fce4caafd4629b670cfc7c0 Mon Sep 17 00:00:00 2001 From: Vsevak Date: Tue, 28 Jan 2020 20:09:40 +0300 Subject: [PATCH 017/577] Merge 'gpu_hip_port' into master --- lib/gpu/Makefile.hip | 148 ++++++++ lib/gpu/geryon/hip_device.h | 519 +++++++++++++++++++++++++++++ lib/gpu/geryon/hip_kernel.h | 298 +++++++++++++++++ lib/gpu/geryon/hip_macros.h | 83 +++++ lib/gpu/geryon/hip_mat.h | 43 +++ lib/gpu/geryon/hip_memory.h | 279 ++++++++++++++++ lib/gpu/geryon/hip_texture.h | 113 +++++++ lib/gpu/geryon/hip_timer.h | 107 ++++++ lib/gpu/geryon/ucl_get_devices.cpp | 5 + lib/gpu/lal_answer.cpp | 17 +- lib/gpu/lal_answer.h | 4 + lib/gpu/lal_atom.cpp | 75 +++++ lib/gpu/lal_atom.cu | 2 +- lib/gpu/lal_atom.h | 13 + lib/gpu/lal_aux_fun1.h | 2 +- lib/gpu/lal_base_atomic.h | 2 + lib/gpu/lal_base_charge.h | 2 + lib/gpu/lal_base_dipole.h | 2 + lib/gpu/lal_base_dpd.h | 2 + lib/gpu/lal_base_ellipsoid.h | 2 + lib/gpu/lal_base_three.h | 2 + lib/gpu/lal_beck.cu | 6 +- lib/gpu/lal_born.cu | 6 +- lib/gpu/lal_born_coul_long.cu | 10 +- lib/gpu/lal_born_coul_long_cs.cu | 11 +- lib/gpu/lal_born_coul_wolf.cu | 10 +- lib/gpu/lal_born_coul_wolf_cs.cu | 10 +- lib/gpu/lal_buck.cu | 6 +- lib/gpu/lal_buck_coul.cu | 10 +- lib/gpu/lal_buck_coul_long.cu | 10 +- lib/gpu/lal_charmm_long.cu | 10 +- lib/gpu/lal_colloid.cu | 6 +- lib/gpu/lal_coul.cu | 10 +- lib/gpu/lal_coul_debye.cu | 10 +- lib/gpu/lal_coul_dsf.cu | 10 +- lib/gpu/lal_coul_long.cu | 10 +- lib/gpu/lal_coul_long_cs.cu | 10 +- lib/gpu/lal_device.cpp | 6 +- lib/gpu/lal_device.cu | 2 +- lib/gpu/lal_dipole_lj.cu | 14 +- lib/gpu/lal_dipole_lj_sf.cu | 14 +- lib/gpu/lal_dipole_long_lj.cu | 14 +- lib/gpu/lal_dpd.cu | 10 +- lib/gpu/lal_eam.cu | 34 +- lib/gpu/lal_ellipsoid_extra.h | 8 +- lib/gpu/lal_ellipsoid_nbor.cu | 6 +- lib/gpu/lal_gauss.cu | 6 +- lib/gpu/lal_gayberne.cu | 2 +- lib/gpu/lal_gayberne_lj.cu | 2 +- lib/gpu/lal_lj.cu | 6 +- lib/gpu/lal_lj96.cu | 6 +- lib/gpu/lal_lj_class2_long.cu | 10 +- lib/gpu/lal_lj_coul.cu | 10 +- lib/gpu/lal_lj_coul_debye.cu | 10 +- lib/gpu/lal_lj_coul_long.cu | 10 +- lib/gpu/lal_lj_coul_msm.cu | 18 +- lib/gpu/lal_lj_cubic.cu | 6 +- lib/gpu/lal_lj_dsf.cu | 10 +- lib/gpu/lal_lj_expand.cu | 6 +- lib/gpu/lal_lj_expand_coul_long.cu | 10 +- lib/gpu/lal_lj_gromacs.cu | 6 +- lib/gpu/lal_lj_sdk.cu | 6 +- lib/gpu/lal_lj_sdk_long.cu | 10 +- lib/gpu/lal_lj_tip4p_long.cpp | 5 +- lib/gpu/lal_lj_tip4p_long.cu | 10 +- lib/gpu/lal_mie.cu | 6 +- lib/gpu/lal_morse.cu | 6 +- lib/gpu/lal_neighbor_cpu.cu | 2 +- lib/gpu/lal_neighbor_gpu.cu | 6 +- lib/gpu/lal_neighbor_shared.h | 4 + lib/gpu/lal_pppm.cu | 10 +- lib/gpu/lal_pppm.h | 2 + lib/gpu/lal_precision.h | 2 + lib/gpu/lal_preprocessor.h | 146 +++++++- lib/gpu/lal_re_squared.cu | 2 +- lib/gpu/lal_re_squared_lj.cu | 2 +- lib/gpu/lal_soft.cu | 6 +- lib/gpu/lal_sw.cu | 18 +- lib/gpu/lal_table.cu | 6 +- lib/gpu/lal_tersoff.cu | 26 +- lib/gpu/lal_tersoff_extra.h | 2 +- lib/gpu/lal_tersoff_mod.cu | 26 +- lib/gpu/lal_tersoff_mod_extra.h | 2 +- lib/gpu/lal_tersoff_zbl.cu | 30 +- lib/gpu/lal_tersoff_zbl_extra.h | 2 +- lib/gpu/lal_ufm.cu | 6 +- lib/gpu/lal_vashishta.cu | 26 +- lib/gpu/lal_yukawa.cu | 6 +- lib/gpu/lal_yukawa_colloid.cu | 10 +- lib/gpu/lal_zbl.cu | 6 +- src/MAKE/OPTIONS/Makefile.hip | 120 +++++++ 91 files changed, 2290 insertions(+), 312 deletions(-) create mode 100644 lib/gpu/Makefile.hip create mode 100644 lib/gpu/geryon/hip_device.h create mode 100644 lib/gpu/geryon/hip_kernel.h create mode 100644 lib/gpu/geryon/hip_macros.h create mode 100644 lib/gpu/geryon/hip_mat.h create mode 100644 lib/gpu/geryon/hip_memory.h create mode 100644 lib/gpu/geryon/hip_texture.h create mode 100644 lib/gpu/geryon/hip_timer.h create mode 100644 src/MAKE/OPTIONS/Makefile.hip diff --git a/lib/gpu/Makefile.hip b/lib/gpu/Makefile.hip new file mode 100644 index 0000000000..5c9f251004 --- /dev/null +++ b/lib/gpu/Makefile.hip @@ -0,0 +1,148 @@ +# /* ---------------------------------------------------------------------- +# Generic Linux Makefile for HIP +# - export HIP_PLATFORM=hcc (or nvcc) before execution +# - change HIP_ARCH for your GPU +# ------------------------------------------------------------------------- */ + +# this setting should match LAMMPS Makefile +# one of LAMMPS_SMALLBIG (default), LAMMPS_BIGBIG and LAMMPS_SMALLSMALL + +LMP_INC = -DLAMMPS_SMALLBIG + +# precision for GPU calculations +# -D_SINGLE_SINGLE # Single precision for all calculations +# -D_DOUBLE_DOUBLE # Double precision for all calculations +# -D_SINGLE_DOUBLE # Accumulation of forces, etc. in double + +HIP_PRECISION = -D_SINGLE_DOUBLE + +HIP_OPTS = -O3 +HIP_HOST_OPTS = -Wno-deprecated-declarations +HIP_HOST_INCLUDE = + +# use device sort +# requires linking with hipcc and hipCUB + (rocPRIM or CUB for AMD or Nvidia respectively) +HIP_HOST_OPTS += -DUSE_HIP_DEVICE_SORT +# path to cub +HIP_HOST_INCLUDE += -I./ +# path to hipcub +HIP_HOST_INCLUDE += -I$(HIP_PATH)/../include + +# use mpi +HIP_HOST_OPTS += -DMPI_GERYON -DUCL_NO_EXIT +# this settings should match LAMMPS Makefile +MPI_COMP_OPTS = $(shell mpicxx --showme:compile) +MPI_LINK_OPTS = $(shell mpicxx --showme:link) +#MPI_COMP_OPTS += -I/usr/include/mpi -DMPICH_IGNORE_CXX_SEEK -DOMPI_SKIP_MPICXX=1 + +HIP_PATH ?= $(wildcard /opt/rocm/hip) +HIP_PLATFORM=$(shell $(HIP_PATH)/bin/hipconfig --compiler) + +ifeq (hcc,$(HIP_PLATFORM)) + HIP_OPTS += -ffast-math + # possible values: gfx803,gfx900,gfx906 + HIP_ARCH = gfx906 +else ifeq (nvcc,$(HIP_PLATFORM)) + HIP_OPTS += --use_fast_math + HIP_ARCH = -gencode arch=compute_30,code=[sm_30,compute_30] -gencode arch=compute_32,code=[sm_32,compute_32] -gencode arch=compute_35,code=[sm_35,compute_35] \ + -gencode arch=compute_50,code=[sm_50,compute_50] -gencode arch=compute_52,code=[sm_52,compute_52] -gencode arch=compute_53,code=[sm_53,compute_53]\ + -gencode arch=compute_60,code=[sm_60,compute_60] -gencode arch=compute_61,code=[sm_61,compute_61] -gencode arch=compute_62,code=[sm_62,compute_62]\ + -gencode arch=compute_70,code=[sm_70,compute_70] -gencode arch=compute_72,code=[sm_72,compute_72] -gencode arch=compute_75,code=[sm_75,compute_75] +else + $(error Specify HIP platform using 'export HIP_PLATFORM=(hcc,nvcc)') +endif + +BIN_DIR = . +OBJ_DIR = ./obj +LIB_DIR = . +AR = ar +BSH = /bin/sh + + +# /* ---------------------------------------------------------------------- +# don't change section below without need +# ------------------------------------------------------------------------- */ + +HIP_OPTS += -DUSE_HIP $(HIP_PRECISION) +HIP_GPU_OPTS += $(HIP_OPTS) -I./ + +ifeq (hcc,$(HIP_PLATFORM)) + HIP_HOST_OPTS += -fPIC + HIP_GPU_CC = $(HIP_PATH)/bin/hipcc --genco + HIP_GPU_OPTS_S = -t="$(HIP_ARCH)" -f=\" + HIP_GPU_OPTS_E = \" + HIP_KERNEL_SUFFIX = .cpp + HIP_LIBS_TARGET = export HCC_AMDGPU_TARGET := $(HIP_ARCH) + export HCC_AMDGPU_TARGET := $(HIP_ARCH) +else ifeq (nvcc,$(HIP_PLATFORM)) + HIP_GPU_CC = $(HIP_PATH)/bin/hipcc --fatbin + HIP_GPU_OPTS += $(HIP_ARCH) + HIP_GPU_SORT_ARCH = $(HIP_ARCH) + # fix nvcc can't handle -pthread flag + MPI_COMP_OPTS := $(subst -pthread,-Xcompiler -pthread,$(MPI_COMP_OPTS)) + MPI_LINK_OPTS := $(subst -pthread,-Xcompiler -pthread,$(MPI_LINK_OPTS)) +endif + +# hipcc is essential for device sort, because of hipcub is header only library and ROCm gpu code generation is deferred to the linking stage +HIP_HOST_CC = $(HIP_PATH)/bin/hipcc +HIP_HOST_OPTS += $(HIP_OPTS) $(MPI_COMP_OPTS) $(LMP_INC) +HIP_HOST_CC_CMD = $(HIP_HOST_CC) $(HIP_HOST_OPTS) $(HIP_HOST_INCLUDE) + +# sources + +ALL_H = $(wildcard ./geryon/ucl*.h) $(wildcard ./geryon/hip*.h) $(wildcard ./lal_*.h) +SRCS := $(wildcard ./lal_*.cpp) +OBJS := $(subst ./,$(OBJ_DIR)/,$(SRCS:%.cpp=%.o)) +CUS := $(wildcard lal_*.cu) +CUHS := $(filter-out pppm_cubin.h, $(CUS:lal_%.cu=%_cubin.h)) pppm_f_cubin.h pppm_d_cubin.h +CUHS := $(addprefix $(OBJ_DIR)/, $(CUHS)) + +all: $(OBJ_DIR) $(CUHS) $(LIB_DIR)/libgpu.a $(BIN_DIR)/hip_get_devices + +$(OBJ_DIR): + mkdir -p $@ + +# GPU kernels compilation + +$(OBJ_DIR)/pppm_f_cubin.h: lal_pppm.cu $(ALL_H) + @cp $< $(OBJ_DIR)/temp_pppm_f.cu$(HIP_KERNEL_SUFFIX) + $(HIP_GPU_CC) $(HIP_GPU_OPTS_S) $(HIP_GPU_OPTS) -Dgrdtyp=float -Dgrdtyp4=float4 $(HIP_GPU_OPTS_E) -o $(OBJ_DIR)/pppm_f.cubin $(OBJ_DIR)/temp_pppm_f.cu$(HIP_KERNEL_SUFFIX) + @xxd -i $(OBJ_DIR)/pppm_f.cubin $@ + @sed -i "s/[a-zA-Z0-9_]*pppm_f_cubin/pppm_f/g" $@ + @rm $(OBJ_DIR)/temp_pppm_f.cu$(HIP_KERNEL_SUFFIX) $(OBJ_DIR)/pppm_f.cubin + +$(OBJ_DIR)/pppm_d_cubin.h: lal_pppm.cu $(ALL_H) + @cp $< $(OBJ_DIR)/temp_pppm_d.cu$(HIP_KERNEL_SUFFIX) + $(HIP_GPU_CC) $(HIP_GPU_OPTS_S) $(HIP_GPU_OPTS) -Dgrdtyp=double -Dgrdtyp4=double4 $(HIP_GPU_OPTS_E) -o $(OBJ_DIR)/pppm_d.cubin $(OBJ_DIR)/temp_pppm_d.cu$(HIP_KERNEL_SUFFIX) + @xxd -i $(OBJ_DIR)/pppm_d.cubin $@ + @sed -i "s/[a-zA-Z0-9_]*pppm_d_cubin/pppm_d/g" $@ + @rm $(OBJ_DIR)/temp_pppm_d.cu$(HIP_KERNEL_SUFFIX) $(OBJ_DIR)/pppm_d.cubin + +$(OBJ_DIR)/%_cubin.h: lal_%.cu $(ALL_H) + @cp $< $(OBJ_DIR)/temp_$*.cu$(HIP_KERNEL_SUFFIX) + $(HIP_GPU_CC) $(HIP_GPU_OPTS_S) $(HIP_GPU_OPTS) $(HIP_GPU_OPTS_E) -o $(OBJ_DIR)/$*.cubin $(OBJ_DIR)/temp_$*.cu$(HIP_KERNEL_SUFFIX) + @xxd -i $(OBJ_DIR)/$*.cubin $@ + @sed -i "s/[a-zA-Z0-9_]*$*_cubin/$*/g" $@ + @rm $(OBJ_DIR)/temp_$*.cu$(HIP_KERNEL_SUFFIX) $(OBJ_DIR)/$*.cubin + +# host sources compilation + +$(OBJ_DIR)/lal_atom.o: lal_atom.cpp $(CUHS) $(ALL_H) + $(HIP_HOST_CC_CMD) -o $@ -c $< -I$(OBJ_DIR) $(HIP_GPU_SORT_ARCH) + +$(OBJ_DIR)/lal_%.o: lal_%.cpp $(CUHS) $(ALL_H) + $(HIP_HOST_CC_CMD) -o $@ -c $< -I$(OBJ_DIR) + +# libgpu building + +$(LIB_DIR)/libgpu.a: $(OBJS) + $(AR) -crs $@ $(OBJS) + echo "export HIP_PLATFORM := $(HIP_PLATFORM)\n$(HIP_LIBS_TARGET)" > 'Makefile.lammps' + +# test app building + +$(BIN_DIR)/hip_get_devices: ./geryon/ucl_get_devices.cpp $(ALL_H) + $(HIP_HOST_CC_CMD) -o $@ $< -DUCL_HIP $(MPI_LINK_OPTS) + +clean: + -rm -f $(BIN_DIR)/hip_get_devices $(LIB_DIR)/libgpu.a $(OBJS) $(OBJ_DIR)/temp_* $(CUHS) diff --git a/lib/gpu/geryon/hip_device.h b/lib/gpu/geryon/hip_device.h new file mode 100644 index 0000000000..93f38d28bb --- /dev/null +++ b/lib/gpu/geryon/hip_device.h @@ -0,0 +1,519 @@ +/* ----------------------------------------------------------------------- + Copyright (2009) 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 Simplified BSD License. + ----------------------------------------------------------------------- */ + +#ifndef HIP_DEVICE +#define HIP_DEVICE + + +#include +#include +#include +#include +#include +#include "hip_macros.h" +#include "ucl_types.h" + +namespace ucl_hip { + +// -------------------------------------------------------------------------- +// - COMMAND QUEUE STUFF +// -------------------------------------------------------------------------- +typedef hipStream_t command_queue; + +inline void ucl_sync(hipStream_t &stream) { + CU_SAFE_CALL(hipStreamSynchronize(stream)); +} + +struct NVDProperties { + int device_id; + std::string name; + int major; + int minor; + CUDA_INT_TYPE totalGlobalMem; + int multiProcessorCount; + + int maxThreadsPerBlock; + int maxThreadsDim[3]; + int maxGridSize[3]; + int sharedMemPerBlock; + int totalConstantMemory; + int SIMDWidth; + int memPitch; + int regsPerBlock; + int clockRate; + int textureAlign; + + int kernelExecTimeoutEnabled; + int integrated; + int canMapHostMemory; + int concurrentKernels; + int ECCEnabled; + int computeMode; +}; + +/// Class for looking at device properties +/** \note Calls to change the device outside of the class results in incorrect + * behavior + * \note There is no error checking for indexing past the number of devices **/ +class UCL_Device { + public: + /// Collect properties for every GPU on the node + /** \note You must set the active GPU with set() before using the device **/ + inline UCL_Device(); + + inline ~UCL_Device(); + + /// Returns 1 (For compatibility with OpenCL) + inline int num_platforms() { return 1; } + + /// Return a string with name and info of the current platform + inline std::string platform_name() + { return "HIP platform"; } + + /// Delete any contexts/data and set the platform number to be used + inline int set_platform(const int pid); + + /// Return the number of devices that support CUDA + inline int num_devices() { return _properties.size(); } + + /// Set the CUDA device to the specified device number + /** A context and default command queue will be created for the device + * Returns UCL_SUCCESS if successful or UCL_ERROR if the device could not + * be allocated for use. clear() is called to delete any contexts and + * associated data from previous calls to set(). **/ + inline int set(int num); + + /// Delete any context and associated data stored from a call to set() + inline void clear(); + + /// Get the current device number + inline int device_num() { return _device; } + + /// Returns the default stream for the current device + inline command_queue & cq() { return cq(0); } + + /// Returns the stream indexed by i + inline command_queue & cq(const int i) { return _cq[i]; } + + /// Block until all commands in the default stream have completed + inline void sync() { sync(0); } + + /// Block until all commands in the specified stream have completed + inline void sync(const int i) { ucl_sync(cq(i)); } + + /// Get the number of command queues currently available on device + inline int num_queues() + { return _cq.size(); } + + /// Add a stream for device computations + inline void push_command_queue() { + _cq.push_back(hipStream_t()); + CU_SAFE_CALL(hipStreamCreateWithFlags(&_cq.back(),0)); + } + + /// Remove a stream for device computations + /** \note You cannot delete the default stream **/ + inline void pop_command_queue() { + if (_cq.size()<2) return; + CU_SAFE_CALL_NS(hipStreamDestroy(_cq.back())); + _cq.pop_back(); + } + + /// Set the default command queue (by default this is the null stream) + /** \param i index of the command queue (as added by push_command_queue()) + If i is 0, the default command queue is set to the null stream **/ + inline void set_command_queue(const int i) { + if (i==0) _cq[0]=0; + else _cq[0]=_cq[i]; + } + + /// Get the current CUDA device name + inline std::string name() { return name(_device); } + /// Get the CUDA device name + inline std::string name(const int i) + { return std::string(_properties[i].name); } + + /// Get a string telling the type of the current device + inline std::string device_type_name() { return device_type_name(_device); } + /// Get a string telling the type of the device + inline std::string device_type_name(const int i) { return "GPU"; } + + /// Get current device type (UCL_CPU, UCL_GPU, UCL_ACCELERATOR, UCL_DEFAULT) + inline int device_type() { return device_type(_device); } + /// Get device type (UCL_CPU, UCL_GPU, UCL_ACCELERATOR, UCL_DEFAULT) + inline int device_type(const int i) { return UCL_GPU; } + + /// Returns true if host memory is efficiently addressable from device + inline bool shared_memory() { return shared_memory(_device); } + /// Returns true if host memory is efficiently addressable from device + inline bool shared_memory(const int i) { return device_type(i)==UCL_CPU; } + + /// Returns true if double precision is support for the current device + inline bool double_precision() { return double_precision(_device); } + /// Returns true if double precision is support for the device + inline bool double_precision(const int i) {return arch(i)>=1.3;} + + /// Get the number of compute units on the current device + inline unsigned cus() { return cus(_device); } + /// Get the number of compute units + inline unsigned cus(const int i) + { return _properties[i].multiProcessorCount; } + + /// Get the number of cores in the current device + inline unsigned cores() { return cores(_device); } + /// Get the number of cores + inline unsigned cores(const int i) + { if (arch(i)<2.0) return _properties[i].multiProcessorCount*8; + else if (arch(i)<2.1) return _properties[i].multiProcessorCount*32; + else if (arch(i)<3.0) return _properties[i].multiProcessorCount*48; + else return _properties[i].multiProcessorCount*192; } + + /// Get the gigabytes of global memory in the current device + inline double gigabytes() { return gigabytes(_device); } + /// Get the gigabytes of global memory + inline double gigabytes(const int i) + { return static_cast(_properties[i].totalGlobalMem)/1073741824; } + + /// Get the bytes of global memory in the current device + inline size_t bytes() { return bytes(_device); } + /// Get the bytes of global memory + inline size_t bytes(const int i) { return _properties[i].totalGlobalMem; } + + // Get the gigabytes of free memory in the current device + inline double free_gigabytes() { return free_gigabytes(_device); } + // Get the gigabytes of free memory + inline double free_gigabytes(const int i) + { return static_cast(free_bytes(i))/1073741824; } + + // Get the bytes of free memory in the current device + inline size_t free_bytes() { return free_bytes(_device); } + // Get the bytes of free memory + inline size_t free_bytes(const int i) { + CUDA_INT_TYPE dfree, dtotal; + CU_SAFE_CALL_NS(hipMemGetInfo(&dfree, &dtotal)); + return static_cast(dfree); + } + + /// Return the GPGPU compute capability for current device + inline double arch() { return arch(_device); } + /// Return the GPGPU compute capability + inline double arch(const int i) + { return static_cast(_properties[i].minor)/10+_properties[i].major;} + + /// Clock rate in GHz for current device + inline double clock_rate() { return clock_rate(_device); } + /// Clock rate in GHz + inline double clock_rate(const int i) + { return _properties[i].clockRate*1e-6;} + + /// Get the maximum number of threads per block + inline size_t group_size() { return group_size(_device); } + /// Get the maximum number of threads per block + inline size_t group_size(const int i) + { return _properties[i].maxThreadsPerBlock; } + + /// Return the maximum memory pitch in bytes for current device + inline size_t max_pitch() { return max_pitch(_device); } + /// Return the maximum memory pitch in bytes + inline size_t max_pitch(const int i) { return _properties[i].memPitch; } + + /// Returns false if accelerator cannot be shared by multiple processes + /** If it cannot be determined, true is returned **/ + inline bool sharing_supported() { return sharing_supported(_device); } + /// Returns false if accelerator cannot be shared by multiple processes + /** If it cannot be determined, true is returned **/ + inline bool sharing_supported(const int i) + { return (_properties[i].computeMode == hipComputeModeDefault); } + + /// True if splitting device into equal subdevices supported + inline bool fission_equal() + { return fission_equal(_device); } + /// True if splitting device into equal subdevices supported + inline bool fission_equal(const int i) + { return false; } + /// True if splitting device into subdevices by specified counts supported + inline bool fission_by_counts() + { return fission_by_counts(_device); } + /// True if splitting device into subdevices by specified counts supported + inline bool fission_by_counts(const int i) + { return false; } + /// True if splitting device into subdevices by affinity domains supported + inline bool fission_by_affinity() + { return fission_by_affinity(_device); } + /// True if splitting device into subdevices by affinity domains supported + inline bool fission_by_affinity(const int i) + { return false; } + + /// Maximum number of subdevices allowed from device fission + inline int max_sub_devices() + { return max_sub_devices(_device); } + /// Maximum number of subdevices allowed from device fission + inline int max_sub_devices(const int i) + { return 0; } + + /// List all devices along with all properties + inline void print_all(std::ostream &out); + + /// Select the platform that has accelerators (for compatibility with OpenCL) + inline int set_platform_accelerator(int pid=-1) { return UCL_SUCCESS; } + + inline int load_module(const void* program, hipModule_t& module, std::string *log=NULL){ + auto it = _loaded_modules.emplace(program, hipModule_t()); + if(!it.second){ + module = it.first->second; + return UCL_SUCCESS; + } + const unsigned int num_opts=2; + hipJitOption options[num_opts]; + void *values[num_opts]; + + // set up size of compilation log buffer + options[0] = hipJitOptionInfoLogBufferSizeBytes; + values[0] = (void *)(int)10240; + // set up pointer to the compilation log buffer + options[1] = hipJitOptionInfoLogBuffer; + char clog[10240] = { 0 }; + values[1] = clog; + + hipError_t err=hipModuleLoadDataEx(&module,program,num_opts, options,(void **)values); + + if (log!=NULL) + *log=std::string(clog); + + if (err != hipSuccess) { + #ifndef UCL_NO_EXIT + std::cerr << std::endl + << "----------------------------------------------------------\n" + << " UCL Error: Error compiling PTX Program...\n" + << "----------------------------------------------------------\n"; + std::cerr << log << std::endl; + #endif + _loaded_modules.erase(it.first); + return UCL_COMPILE_ERROR; + } + it.first->second = module; + return UCL_SUCCESS; + } + private: + std::unordered_map _loaded_modules; + int _device, _num_devices; + std::vector _properties; + std::vector _cq; + hipDevice_t _cu_device; +}; + +// Grabs the properties for all devices +UCL_Device::UCL_Device() { + CU_SAFE_CALL_NS(hipInit(0)); + CU_SAFE_CALL_NS(hipGetDeviceCount(&_num_devices)); + for (int i=0; i<_num_devices; ++i) { + hipDevice_t dev; + CU_SAFE_CALL_NS(hipDeviceGet(&dev,i)); + int major, minor; + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&major, hipDeviceAttributeComputeCapabilityMajor, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&minor, hipDeviceAttributeComputeCapabilityMinor, dev)); + if (major==9999) + continue; + + NVDProperties prop; + prop.device_id = i; + prop.major=major; + prop.minor=minor; + + char namecstr[1024]; + CU_SAFE_CALL_NS(hipDeviceGetName(namecstr,1024,dev)); + prop.name=namecstr; + + CU_SAFE_CALL_NS(hipDeviceTotalMem(&prop.totalGlobalMem,dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.multiProcessorCount, hipDeviceAttributeMultiprocessorCount, dev)); + + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxThreadsPerBlock, hipDeviceAttributeMaxThreadsPerBlock, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxThreadsDim[0], hipDeviceAttributeMaxBlockDimX, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxThreadsDim[1], hipDeviceAttributeMaxBlockDimY, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxThreadsDim[2], hipDeviceAttributeMaxBlockDimZ, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxGridSize[0], hipDeviceAttributeMaxGridDimX, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxGridSize[1], hipDeviceAttributeMaxGridDimY, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.maxGridSize[2], hipDeviceAttributeMaxGridDimZ, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.sharedMemPerBlock, hipDeviceAttributeMaxSharedMemoryPerBlock, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.totalConstantMemory, hipDeviceAttributeTotalConstantMemory, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.SIMDWidth, hipDeviceAttributeWarpSize, dev)); + //CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.memPitch, CU_DEVICE_ATTRIBUTE_MAX_PITCH, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.regsPerBlock, hipDeviceAttributeMaxRegistersPerBlock, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.clockRate, hipDeviceAttributeClockRate, dev)); + //CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.textureAlign, CU_DEVICE_ATTRIBUTE_TEXTURE_ALIGNMENT, dev)); + + //#if CUDA_VERSION >= 2020 + //CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.kernelExecTimeoutEnabled, CU_DEVICE_ATTRIBUTE_KERNEL_EXEC_TIMEOUT,dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.integrated, hipDeviceAttributeIntegrated, dev)); + //CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.canMapHostMemory, CU_DEVICE_ATTRIBUTE_CAN_MAP_HOST_MEMORY, dev)); + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.computeMode, hipDeviceAttributeComputeMode,dev)); + //#endif + //#if CUDA_VERSION >= 3010 + CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.concurrentKernels, hipDeviceAttributeConcurrentKernels, dev)); + //CU_SAFE_CALL_NS(hipDeviceGetAttribute(&prop.ECCEnabled, CU_DEVICE_ATTRIBUTE_ECC_ENABLED, dev)); + //#endif + + _properties.push_back(prop); + } + _device=-1; + _cq.push_back(hipStream_t()); + _cq.back()=0; +} + +UCL_Device::~UCL_Device() { + clear(); +} + +int UCL_Device::set_platform(const int pid) { + clear(); + #ifdef UCL_DEBUG + assert(pid-1) { + for (int i=1; i= 2020 + int driver_version; + hipDriverGetVersion(&driver_version); + out << "Driver Version: " + << driver_version/1000 << "." << driver_version%100 + << std::endl; + //#endif + + if (num_devices() == 0) + out << "There is no device supporting HIP\n"; + for (int i=0; i= 2000 + out << " Number of compute units/multiprocessors: " + << _properties[i].multiProcessorCount << std::endl; + out << " Number of cores: " + << cores(i) << std::endl; + //#endif + out << " Total amount of constant memory: " + << _properties[i].totalConstantMemory << " bytes\n"; + out << " Total amount of local/shared memory per block: " + << _properties[i].sharedMemPerBlock << " bytes\n"; + out << " Total number of registers available per block: " + << _properties[i].regsPerBlock << std::endl; + out << " Warp size: " + << _properties[i].SIMDWidth << std::endl; + out << " Maximum number of threads per block: " + << _properties[i].maxThreadsPerBlock << std::endl; + out << " Maximum group size (# of threads per block) " + << _properties[i].maxThreadsDim[0] << " x " + << _properties[i].maxThreadsDim[1] << " x " + << _properties[i].maxThreadsDim[2] << std::endl; + out << " Maximum item sizes (# threads for each dim) " + << _properties[i].maxGridSize[0] << " x " + << _properties[i].maxGridSize[1] << " x " + << _properties[i].maxGridSize[2] << std::endl; + //out << " Maximum memory pitch: " + // << max_pitch(i) << " bytes\n"; + //out << " Texture alignment: " + // << _properties[i].textureAlign << " bytes\n"; + out << " Clock rate: " + << clock_rate(i) << " GHz\n"; + //#if CUDA_VERSION >= 2020 + //out << " Run time limit on kernels: "; + //if (_properties[i].kernelExecTimeoutEnabled) + // out << "Yes\n"; + //else + // out << "No\n"; + out << " Integrated: "; + if (_properties[i].integrated) + out << "Yes\n"; + else + out << "No\n"; + //out << " Support host page-locked memory mapping: "; + //if (_properties[i].canMapHostMemory) + // out << "Yes\n"; + //else + // out << "No\n"; + out << " Compute mode: "; + if (_properties[i].computeMode == hipComputeModeDefault) + out << "Default\n"; // multiple threads can use device +//#if CUDA_VERSION >= 8000 +// else if (_properties[i].computeMode == hipComputeModeExclusiveProcess) +//#else + else if (_properties[i].computeMode == hipComputeModeExclusive) +//#endif + out << "Exclusive\n"; // only thread can use device + else if (_properties[i].computeMode == hipComputeModeProhibited) + out << "Prohibited\n"; // no thread can use device + //#if CUDART_VERSION >= 4000 + else if (_properties[i].computeMode == hipComputeModeExclusiveProcess) + out << "Exclusive Process\n"; // multiple threads 1 process + //#endif + else + out << "Unknown\n"; + //#endif + //#if CUDA_VERSION >= 3010 + out << " Concurrent kernel execution: "; + if (_properties[i].concurrentKernels) + out << "Yes\n"; + else + out << "No\n"; + //out << " Device has ECC support enabled: "; + //if (_properties[i].ECCEnabled) + // out << "Yes\n"; + //else + // out << "No\n"; + //#endif + } +} + +} + +#endif diff --git a/lib/gpu/geryon/hip_kernel.h b/lib/gpu/geryon/hip_kernel.h new file mode 100644 index 0000000000..654eb44772 --- /dev/null +++ b/lib/gpu/geryon/hip_kernel.h @@ -0,0 +1,298 @@ +/* ----------------------------------------------------------------------- + Copyright (2010) 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 Simplified BSD License. + ----------------------------------------------------------------------- */ + +#ifndef HIP_KERNEL +#define HIP_KERNEL + + +#include +#include "hip_device.h" +#include +#include +#include + +namespace ucl_hip { + +class UCL_Texture; +template class UCL_D_Vec; +template class UCL_D_Mat; +template class UCL_Vector; +template class UCL_Matrix; +#define UCL_MAX_KERNEL_ARGS 256 + +/// Class storing 1 or more kernel functions from a single string or file +class UCL_Program { + UCL_Device* _device_ptr; + public: + inline UCL_Program(UCL_Device &device) { _device_ptr = &device; _cq=device.cq(); } + inline UCL_Program(UCL_Device &device, const void *program, + const char *flags="", std::string *log=NULL) { + _device_ptr = &device; _cq=device.cq(); + init(device); + load_string(program,flags,log); + } + + inline ~UCL_Program() {} + + /// Initialize the program with a device + inline void init(UCL_Device &device) { _device_ptr = &device; _cq=device.cq(); } + + /// Clear any data associated with program + /** \note Must call init() after each clear **/ + inline void clear() { } + + /// Load a program from a file and compile with flags + inline int load(const char *filename, const char *flags="", std::string *log=NULL) { + std::ifstream in(filename); + if (!in || in.is_open()==false) { + #ifndef UCL_NO_EXIT + std::cerr << "UCL Error: Could not open kernel file: " + << filename << std::endl; + UCL_GERYON_EXIT; + #endif + return UCL_FILE_NOT_FOUND; + } + + std::string program((std::istreambuf_iterator(in)), + std::istreambuf_iterator()); + in.close(); + return load_string(program.c_str(),flags,log); + } + + /// Load a program from a string and compile with flags + inline int load_string(const void *program, const char *flags="", std::string *log=NULL) { + return _device_ptr->load_module(program, _module, log); + } + + friend class UCL_Kernel; + private: + hipModule_t _module; + hipStream_t _cq; + friend class UCL_Texture; +}; + +/// Class for dealing with CUDA Driver kernels +class UCL_Kernel { + public: + UCL_Kernel() : _dimensions(1), _num_args(0) { + _num_blocks[0]=0; + } + + UCL_Kernel(UCL_Program &program, const char *function) : + _dimensions(1), _num_args(0) { + _num_blocks[0]=0; + set_function(program,function); + _cq=program._cq; + } + + ~UCL_Kernel() {} + + /// Clear any function associated with the kernel + inline void clear() { } + + /// Get the kernel function from a program + /** \ret UCL_ERROR_FLAG (UCL_SUCCESS, UCL_FILE_NOT_FOUND, UCL_ERROR) **/ + inline int set_function(UCL_Program &program, const char *function) { + hipError_t err=hipModuleGetFunction(&_kernel,program._module,function); + if (err!=hipSuccess) { + #ifndef UCL_NO_EXIT + std::cerr << "UCL Error: Could not find function: " << function + << " in program.\n"; + UCL_GERYON_EXIT; + #endif + return UCL_FUNCTION_NOT_FOUND; + } + _cq=program._cq; + return UCL_SUCCESS; + } + + /// Set the kernel argument. + /** If not a device pointer, this must be repeated each time the argument + * changes + * \note To set kernel parameter i (i>0), parameter i-1 must be set **/ + template + inline void set_arg(const unsigned index, const dtype * const arg) { + if (index==_num_args) + add_arg(arg); + else if (index<_num_args){ + assert(0==1); // not implemented + } + else + assert(0==1); // Must add kernel parameters in sequential order + } + + /// Set a geryon container as a kernel argument. + template + inline void set_arg(const UCL_D_Vec * const arg) + { set_arg(&arg->begin()); } + + /// Set a geryon container as a kernel argument. + template + inline void set_arg(const UCL_D_Mat * const arg) + { set_arg(&arg->begin()); } + + /// Set a geryon container as a kernel argument. + template + inline void set_arg(const UCL_Vector * const arg) + { set_arg(&arg->device.begin()); } + + /// Set a geryon container as a kernel argument. + template + inline void set_arg(const UCL_Matrix * const arg) + { set_arg(&arg->device.begin()); } + + /// Add a kernel argument. + inline void add_arg(const hipDeviceptr_t* const arg) { + add_arg((void**)arg); + } + + /// Add a kernel argument. + template + inline void add_arg(const dtype* const arg) { + const auto old_size = _hip_kernel_args.size(); + const auto aligned_size = (old_size+alignof(dtype)-1) & ~(alignof(dtype)-1); + const auto arg_size = sizeof(dtype); + _hip_kernel_args.resize(aligned_size + arg_size); + *((dtype*)(&_hip_kernel_args[aligned_size])) = *arg; + _num_args++; + if (_num_args>UCL_MAX_KERNEL_ARGS) assert(0==1); + } + + /// Add a geryon container as a kernel argument. + template + inline void add_arg(const UCL_D_Vec * const arg) + { add_arg(&arg->begin()); } + + /// Add a geryon container as a kernel argument. + template + inline void add_arg(const UCL_D_Mat * const arg) + { add_arg(&arg->begin()); } + + /// Add a geryon container as a kernel argument. + template + inline void add_arg(const UCL_Vector * const arg) + { add_arg(&arg->device.begin()); } + + /// Add a geryon container as a kernel argument. + template + inline void add_arg(const UCL_Matrix * const arg) + { add_arg(&arg->device.begin()); } + + /// Set the number of thread blocks and the number of threads in each block + /** \note This should be called before any arguments have been added + \note The default command queue is used for the kernel execution **/ + inline void set_size(const size_t num_blocks, const size_t block_size) { + _dimensions=1; + _num_blocks[0]=num_blocks; + _num_blocks[1]=1; + _num_blocks[2]=1; + + _block_size[0]=block_size; + _block_size[1]=1; + _block_size[2]=1; + } + + /// Set the number of thread blocks and the number of threads in each block + /** \note This should be called before any arguments have been added + \note The default command queue for the kernel is changed to cq **/ + inline void set_size(const size_t num_blocks, const size_t block_size, + command_queue &cq) + { _cq=cq; set_size(num_blocks,block_size); } + + /// Set the number of thread blocks and the number of threads in each block + /** \note This should be called before any arguments have been added + \note The default command queue is used for the kernel execution **/ + inline void set_size(const size_t num_blocks_x, const size_t num_blocks_y, + const size_t block_size_x, const size_t block_size_y) { + _dimensions=2; + _num_blocks[0]=num_blocks_x; + _num_blocks[1]=num_blocks_y; + _num_blocks[2]=1; + + _block_size[0]=block_size_x; + _block_size[1]=block_size_y; + _block_size[2]=1; + } + + /// Set the number of thread blocks and the number of threads in each block + /** \note This should be called before any arguments have been added + \note The default command queue for the kernel is changed to cq **/ + inline void set_size(const size_t num_blocks_x, const size_t num_blocks_y, + const size_t block_size_x, const size_t block_size_y, + command_queue &cq) + {_cq=cq; set_size(num_blocks_x, num_blocks_y, block_size_x, block_size_y);} + + /// Set the number of thread blocks and the number of threads in each block + /** \note This should be called before any arguments have been added + \note The default command queue is used for the kernel execution **/ + inline void set_size(const size_t num_blocks_x, const size_t num_blocks_y, + const size_t block_size_x, + const size_t block_size_y, const size_t block_size_z) { + _dimensions=2; + _num_blocks[0]=num_blocks_x; + _num_blocks[1]=num_blocks_y; + _num_blocks[2]=1; + + _block_size[0]=block_size_x; + _block_size[1]=block_size_y; + _block_size[2]=block_size_z; + } + + /// Set the number of thread blocks and the number of threads in each block + /** \note This should be called before any arguments have been added + \note The default command queue is used for the kernel execution **/ + inline void set_size(const size_t num_blocks_x, const size_t num_blocks_y, + const size_t block_size_x, const size_t block_size_y, + const size_t block_size_z, command_queue &cq) { + _cq=cq; + set_size(num_blocks_x, num_blocks_y, block_size_x, block_size_y, + block_size_z); + } + + /// Run the kernel in the default command queue + inline void run() { + size_t args_size = _hip_kernel_args.size(); + void *config[] = { + HIP_LAUNCH_PARAM_BUFFER_POINTER, (void*)_hip_kernel_args.data(), + HIP_LAUNCH_PARAM_BUFFER_SIZE, &args_size, + HIP_LAUNCH_PARAM_END + }; + const auto res = hipModuleLaunchKernel(_kernel,_num_blocks[0],_num_blocks[1], + _num_blocks[2],_block_size[0],_block_size[1], + _block_size[2],0,_cq, NULL, config); + CU_SAFE_CALL(res); +//#endif + } + + /// Clear any arguments associated with the kernel + inline void clear_args() { + _num_args=0; + _hip_kernel_args.clear(); + } + + /// Return the default command queue/stream associated with this data + inline command_queue & cq() { return _cq; } + /// Change the default command queue associated with matrix + inline void cq(command_queue &cq_in) { _cq=cq_in; } + #include "ucl_arg_kludge.h" + + private: + hipFunction_t _kernel; + hipStream_t _cq; + unsigned _dimensions; + unsigned _num_blocks[3]; + unsigned _num_args; + friend class UCL_Texture; + + unsigned _block_size[3]; + std::vector _hip_kernel_args; +}; + +} // namespace + +#endif + diff --git a/lib/gpu/geryon/hip_macros.h b/lib/gpu/geryon/hip_macros.h new file mode 100644 index 0000000000..9c9971b896 --- /dev/null +++ b/lib/gpu/geryon/hip_macros.h @@ -0,0 +1,83 @@ +#ifndef HIP_MACROS_H +#define HIP_MACROS_H + +#include +#include +#include + +//#if CUDA_VERSION >= 3020 +#define CUDA_INT_TYPE size_t +//#else +//#define CUDA_INT_TYPE unsigned +//#endif + +#ifdef MPI_GERYON +#include "mpi.h" +#define NVD_GERYON_EXIT do { \ + int is_final; \ + MPI_Finalized(&is_final); \ + if (!is_final) \ + MPI_Abort(MPI_COMM_WORLD,-1); \ + } while(0) +#else +#define NVD_GERYON_EXIT assert(0==1) +#endif + +#ifndef UCL_GERYON_EXIT +#define UCL_GERYON_EXIT NVD_GERYON_EXIT +#endif + +#ifdef UCL_DEBUG +#define UCL_SYNC_DEBUG +#define UCL_DESTRUCT_CHECK +#endif + +#ifndef UCL_NO_API_CHECK + +#define CU_SAFE_CALL_NS( call ) do { \ + hipError_t err = call; \ + if( hipSuccess != err) { \ + fprintf(stderr, "HIP runtime error %d in call at file '%s' in line %i.\n", \ + err, __FILE__, __LINE__ ); \ + NVD_GERYON_EXIT; \ + } } while (0) + +#ifdef UCL_SYNC_DEBUG + +#define CU_SAFE_CALL( call ) do { \ + CU_SAFE_CALL_NS( call ); \ + hipError_t err=hipCtxSynchronize(); \ + if( hipSuccess != err) { \ + fprintf(stderr, "HIP runtime error %d in file '%s' in line %i.\n", \ + err, __FILE__, __LINE__ ); \ + NVD_GERYON_EXIT; \ + } } while (0) + +#else + +#define CU_SAFE_CALL( call ) CU_SAFE_CALL_NS( call ) + +#endif + +#else // not DEBUG + +// void macros for performance reasons +#define CU_SAFE_CALL_NS( call ) call +#define CU_SAFE_CALL( call) call + +#endif + +#ifdef UCL_DESTRUCT_CHECK + +#define CU_DESTRUCT_CALL( call) CU_SAFE_CALL( call) +#define CU_DESTRUCT_CALL_NS( call) CU_SAFE_CALL_NS( call) + +#else + +#define CU_DESTRUCT_CALL( call) call +#define CU_DESTRUCT_CALL_NS( call) call + +#endif + +#endif + diff --git a/lib/gpu/geryon/hip_mat.h b/lib/gpu/geryon/hip_mat.h new file mode 100644 index 0000000000..d9bbb4e521 --- /dev/null +++ b/lib/gpu/geryon/hip_mat.h @@ -0,0 +1,43 @@ +/* ----------------------------------------------------------------------- + Copyright (2010) 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 Simplified BSD License. + ----------------------------------------------------------------------- */ + +/*! \file */ + +#ifndef HIP_MAT_H +#define HIP_MAT_H + + +#include +#include "hip_memory.h" + +/// Namespace for CUDA Driver routines +namespace ucl_hip { + +#define _UCL_MAT_ALLOW +#define _UCL_DEVICE_PTR_MAT +#include "ucl_basemat.h" +#include "ucl_h_vec.h" +#include "ucl_h_mat.h" +#include "ucl_d_vec.h" +#include "ucl_d_mat.h" +#include "ucl_s_obj_help.h" +#include "ucl_vector.h" +#include "ucl_matrix.h" +#undef _UCL_DEVICE_PTR_MAT +#undef _UCL_MAT_ALLOW + +#define UCL_COPY_ALLOW +#include "ucl_copy.h" +#undef UCL_COPY_ALLOW + +#define UCL_PRINT_ALLOW +#include "ucl_print.h" +#undef UCL_PRINT_ALLOW + +} // namespace ucl_cudadr + +#endif diff --git a/lib/gpu/geryon/hip_memory.h b/lib/gpu/geryon/hip_memory.h new file mode 100644 index 0000000000..13f60ad939 --- /dev/null +++ b/lib/gpu/geryon/hip_memory.h @@ -0,0 +1,279 @@ +/* ----------------------------------------------------------------------- + Copyright (2010) 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 Simplified BSD License. + ----------------------------------------------------------------------- */ + +#ifndef HIP_MEMORY_H +#define HIP_MEMORY_H + + +#include +#include +#include +#include +#include "hip_macros.h" +#include "hip_device.h" +#include "ucl_types.h" + +namespace ucl_hip { + +// -------------------------------------------------------------------------- +// - API Specific Types +// -------------------------------------------------------------------------- +//typedef dim3 ucl_kernel_dim; + +#ifdef __HIP_PLATFORM_NVCC__ +typedef enum hipArray_Format { + HIP_AD_FORMAT_UNSIGNED_INT8 = 0x01, + HIP_AD_FORMAT_UNSIGNED_INT16 = 0x02, + HIP_AD_FORMAT_UNSIGNED_INT32 = 0x03, + HIP_AD_FORMAT_SIGNED_INT8 = 0x08, + HIP_AD_FORMAT_SIGNED_INT16 = 0x09, + HIP_AD_FORMAT_SIGNED_INT32 = 0x0a, + HIP_AD_FORMAT_HALF = 0x10, + HIP_AD_FORMAT_FLOAT = 0x20 +}hipArray_Format; +#endif + +// -------------------------------------------------------------------------- +// - API SPECIFIC DEVICE POINTERS +// -------------------------------------------------------------------------- +typedef hipDeviceptr_t device_ptr; + +// -------------------------------------------------------------------------- +// - HOST MEMORY ALLOCATION ROUTINES +// -------------------------------------------------------------------------- +template +inline int _host_alloc(mat_type &mat, copy_type &cm, const size_t n, + const enum UCL_MEMOPT kind, const enum UCL_MEMOPT kind2){ + hipError_t err=hipSuccess; + if (kind==UCL_NOT_PINNED) + *(mat.host_ptr())=(typename mat_type::data_type*)malloc(n); + else if (kind==UCL_WRITE_ONLY) + err=hipHostMalloc((void **)mat.host_ptr(),n,hipHostMallocWriteCombined); + else + err=hipHostMalloc((void **)mat.host_ptr(),n,hipHostMallocDefault); + if (err!=hipSuccess || *(mat.host_ptr())==NULL) + return UCL_MEMORY_ERROR; + mat.cq()=cm.cq(); + return UCL_SUCCESS; +} + +template +inline int _host_alloc(mat_type &mat, UCL_Device &dev, const size_t n, + const enum UCL_MEMOPT kind, const enum UCL_MEMOPT kind2){ + hipError_t err=hipSuccess; + if (kind==UCL_NOT_PINNED) + *(mat.host_ptr())=(typename mat_type::data_type*)malloc(n); + else if (kind==UCL_WRITE_ONLY) + err=hipHostMalloc((void **)mat.host_ptr(),n,hipHostMallocWriteCombined); + else + err=hipHostMalloc((void **)mat.host_ptr(),n,hipHostMallocDefault); + if (err!=hipSuccess || *(mat.host_ptr())==NULL) + return UCL_MEMORY_ERROR; + mat.cq()=dev.cq(); + return UCL_SUCCESS; +} + +template +inline void _host_free(mat_type &mat) { + if (mat.kind()==UCL_VIEW) + return; + else if (mat.kind()!=UCL_NOT_PINNED) + CU_DESTRUCT_CALL(hipHostFree(mat.begin())); + else + free(mat.begin()); +} + +template +inline int _host_resize(mat_type &mat, const size_t n) { + _host_free(mat); + hipError_t err=hipSuccess; + if (mat.kind()==UCL_NOT_PINNED) + *(mat.host_ptr())=(typename mat_type::data_type*)malloc(n); + else if (mat.kind()==UCL_WRITE_ONLY) + err=hipHostMalloc((void **)mat.host_ptr(),n,hipHostMallocWriteCombined); + else + err=hipHostMalloc((void **)mat.host_ptr(),n,hipHostMallocDefault); + if (err!=hipSuccess || *(mat.host_ptr())==NULL) + return UCL_MEMORY_ERROR; + return UCL_SUCCESS; +} + +// -------------------------------------------------------------------------- +// - DEVICE MEMORY ALLOCATION ROUTINES +// -------------------------------------------------------------------------- +template +inline int _device_alloc(mat_type &mat, copy_type &cm, const size_t n, + const enum UCL_MEMOPT kind) { + hipError_t err=hipMalloc((void**)&mat.cbegin(),n); + if (err!=hipSuccess) + return UCL_MEMORY_ERROR; + mat.cq()=cm.cq(); + return UCL_SUCCESS; +} + +template +inline int _device_alloc(mat_type &mat, UCL_Device &dev, const size_t n, + const enum UCL_MEMOPT kind) { + hipError_t err=hipMalloc((void**)&mat.cbegin(),n); + if (err!=hipSuccess) + return UCL_MEMORY_ERROR; + mat.cq()=dev.cq(); + return UCL_SUCCESS; +} + +template +inline int _device_alloc(mat_type &mat, copy_type &cm, const size_t rows, + const size_t cols, size_t &pitch, + const enum UCL_MEMOPT kind) { + hipError_t err; + size_t upitch; + err=hipMallocPitch((void**)&mat.cbegin(),&upitch, + cols*sizeof(typename mat_type::data_type),rows); + pitch=static_cast(upitch); + if (err!=hipSuccess) + return UCL_MEMORY_ERROR; + mat.cq()=cm.cq(); + return UCL_SUCCESS; +} + +template +inline int _device_alloc(mat_type &mat, UCL_Device &d, const size_t rows, + const size_t cols, size_t &pitch, + const enum UCL_MEMOPT kind) { + hipError_t err; + size_t upitch; + err=hipMallocPitch((void**)&mat.cbegin(),&upitch, + cols*sizeof(typename mat_type::data_type),rows); + pitch=static_cast(upitch); + if (err!=hipSuccess) + return UCL_MEMORY_ERROR; + mat.cq()=d.cq(); + return UCL_SUCCESS; +} + +template +inline void _device_free(mat_type &mat) { + if (mat.kind()!=UCL_VIEW){ + CU_DESTRUCT_CALL(hipFree((void*)mat.cbegin())); + } +} + +template +inline int _device_resize(mat_type &mat, const size_t n) { + _device_free(mat); + hipError_t err=hipMalloc((void**)&mat.cbegin(),n); + if (err!=hipSuccess) + return UCL_MEMORY_ERROR; + return UCL_SUCCESS; +} + +template +inline int _device_resize(mat_type &mat, const size_t rows, + const size_t cols, size_t &pitch) { + _device_free(mat); + hipError_t err; + size_t upitch; + err=hipMallocPitch((void**)&mat.cbegin(),&upitch, + cols*sizeof(typename mat_type::data_type),rows); + pitch=static_cast(upitch); + if (err!=hipSuccess) + return UCL_MEMORY_ERROR; + return UCL_SUCCESS; +} + +inline void _device_view(hipDeviceptr_t *ptr, hipDeviceptr_t &in) { + *ptr=in; +} + +template +inline void _device_view(hipDeviceptr_t *ptr, numtyp *in) { + *ptr=0; +} + +inline void _device_view(hipDeviceptr_t *ptr, hipDeviceptr_t &in, + const size_t offset, const size_t numsize) { + *ptr=(hipDeviceptr_t)(((char*)in)+offset*numsize); +} + +template +inline void _device_view(hipDeviceptr_t *ptr, numtyp *in, + const size_t offset, const size_t numsize) { + *ptr=0; +} + +// -------------------------------------------------------------------------- +// - DEVICE IMAGE ALLOCATION ROUTINES +// -------------------------------------------------------------------------- +template +inline void _device_image_alloc(mat_type &mat, copy_type &cm, const size_t rows, + const size_t cols) { + assert(0==1); +} + +template +inline void _device_image_alloc(mat_type &mat, UCL_Device &d, const size_t rows, + const size_t cols) { + assert(0==1); +} + +template +inline void _device_image_free(mat_type &mat) { + assert(0==1); +} + +// -------------------------------------------------------------------------- +// - ZERO ROUTINES +// -------------------------------------------------------------------------- +inline void _host_zero(void *ptr, const size_t n) { + memset(ptr,0,n); +} + +template +inline void _device_zero(mat_type &mat, const size_t n, command_queue &cq) { + CU_SAFE_CALL(hipMemsetAsync((void*)mat.cbegin(),0,n,cq)); +} + + +// -------------------------------------------------------------------------- +// - MEMCPY ROUTINES +// -------------------------------------------------------------------------- + + +template +hipMemcpyKind _memcpy_kind(mat1 &dst, const mat2 &src){ + assert(mat1::MEM_TYPE < 2 && mat2::MEM_TYPE < 2); + return (hipMemcpyKind)((1 - mat2::MEM_TYPE)*2 + (1 - mat1::MEM_TYPE)); +} + +template +inline void ucl_mv_cpy(mat1 &dst, const mat2 &src, const size_t n) { + CU_SAFE_CALL(hipMemcpy((void*)dst.begin(), (void*)src.begin(), n, _memcpy_kind(dst, src))); +} + +template +inline void ucl_mv_cpy(mat1 &dst, const mat2 &src, const size_t n, hipStream_t &cq) { + CU_SAFE_CALL(hipMemcpyAsync((void*)dst.begin(), (void*)src.begin(), n, _memcpy_kind(dst, src), cq)); +} + +template +inline void ucl_mv_cpy(mat1 &dst, const size_t dpitch, const mat2 &src, + const size_t spitch, const size_t cols, + const size_t rows) { + CU_SAFE_CALL(hipMemcpy2D((void*)dst.begin(), dpitch, (void*)src.begin(), spitch, cols, rows, _memcpy_kind(dst, src))); +} + +template +inline void ucl_mv_cpy(mat1 &dst, const size_t dpitch, const mat2 &src, + const size_t spitch, const size_t cols, + const size_t rows,hipStream_t &cq) { + CU_SAFE_CALL(hipMemcpy2DAsync((void*)dst.begin(), dpitch, (void*)src.begin(), spitch, cols, rows, _memcpy_kind(dst, src), cq)); +} + +} // namespace ucl_cudart + +#endif + diff --git a/lib/gpu/geryon/hip_texture.h b/lib/gpu/geryon/hip_texture.h new file mode 100644 index 0000000000..e7aa4e1461 --- /dev/null +++ b/lib/gpu/geryon/hip_texture.h @@ -0,0 +1,113 @@ +/* ----------------------------------------------------------------------- + Copyright (2010) 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 Simplified BSD License. + ----------------------------------------------------------------------- */ + +#ifndef HIP_TEXTURE +#define HIP_TEXTURE + + +#include +#include "hip_kernel.h" +#include "hip_mat.h" + +namespace ucl_hip { + +#ifdef __HIP_PLATFORM_NVCC__ +inline hipError_t hipModuleGetTexRef(CUtexref* texRef, hipModule_t hmod, const char* name){ + return hipCUResultTohipError(cuModuleGetTexRef(texRef, hmod, name)); +} +inline hipError_t hipTexRefSetFormat(CUtexref tex, hipArray_Format fmt, int NumPackedComponents) { + return hipCUResultTohipError(cuTexRefSetFormat(tex, (CUarray_format)fmt, NumPackedComponents )); +} +inline hipError_t hipTexRefSetAddress(size_t* offset, CUtexref tex, hipDeviceptr_t devPtr, size_t size) { + return hipCUResultTohipError(cuTexRefSetAddress(offset, tex, devPtr, size)); +} +#endif + +/// Class storing a texture reference +class UCL_Texture { + public: + UCL_Texture() {} + ~UCL_Texture() {} + /// Construct with a specified texture reference + inline UCL_Texture(UCL_Program &prog, const char *texture_name) + { get_texture(prog,texture_name); } + /// Set the texture reference for this object + inline void get_texture(UCL_Program &prog, const char *texture_name) + { + #ifdef __HIP_PLATFORM_NVCC__ + CU_SAFE_CALL(hipModuleGetTexRef(&_tex, prog._module, texture_name)); + #else + size_t _global_var_size; + CU_SAFE_CALL(hipModuleGetGlobal(&_device_ptr_to_global_var, &_global_var_size, prog._module, texture_name)); + #endif + } + + /// Bind a float array where each fetch grabs a vector of length numel + template + inline void bind_float(UCL_D_Vec &vec, const unsigned numel) + { _bind_float(vec,numel); } + + /// Bind a float array where each fetch grabs a vector of length numel + template + inline void bind_float(UCL_D_Mat &vec, const unsigned numel) + { _bind_float(vec,numel); } + + /// Bind a float array where each fetch grabs a vector of length numel + template + inline void bind_float(UCL_Vector &vec, const unsigned numel) + { _bind_float(vec.device,numel); } + + /// Bind a float array where each fetch grabs a vector of length numel + template + inline void bind_float(UCL_Matrix &vec, const unsigned numel) + { _bind_float(vec.device,numel); } + + /// Unbind the texture reference from the memory allocation + inline void unbind() { } + + /// Make a texture reference available to kernel + inline void allow(UCL_Kernel &kernel) { + //#if CUDA_VERSION < 4000 + //CU_SAFE_CALL(cuParamSetTexRef(kernel._kernel, CU_PARAM_TR_DEFAULT, _tex)); + //#endif + } + + private: +#ifdef __HIP_PLATFORM_NVCC__ + CUtexref _tex; +#else + void* _device_ptr_to_global_var; +#endif + friend class UCL_Kernel; + + template + inline void _bind_float(mat_typ &vec, const unsigned numel) { + #ifdef UCL_DEBUG + assert(numel!=0 && numel<5); + #endif + +#ifdef __HIP_PLATFORM_NVCC__ + if (vec.element_size()==sizeof(float)) + CU_SAFE_CALL(hipTexRefSetFormat(_tex, HIP_AD_FORMAT_FLOAT, numel)); + else { + if (numel>2) + CU_SAFE_CALL(hipTexRefSetFormat(_tex, HIP_AD_FORMAT_SIGNED_INT32, numel)); + else + CU_SAFE_CALL(hipTexRefSetFormat(_tex,HIP_AD_FORMAT_SIGNED_INT32,numel*2)); + } + CU_SAFE_CALL(hipTexRefSetAddress(NULL, _tex, vec.cbegin(), vec.numel()*vec.element_size())); +#else + void* data_ptr = (void*)vec.cbegin(); + CU_SAFE_CALL(hipMemcpyHtoD(hipDeviceptr_t(_device_ptr_to_global_var), &data_ptr, sizeof(void*))); +#endif + } +}; + +} // namespace + +#endif + diff --git a/lib/gpu/geryon/hip_timer.h b/lib/gpu/geryon/hip_timer.h new file mode 100644 index 0000000000..3be0b8cfd6 --- /dev/null +++ b/lib/gpu/geryon/hip_timer.h @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------------- + Copyright (2010) 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 Simplified BSD License. + ----------------------------------------------------------------------- */ + +#ifndef HIP_TIMER_H +#define HIP_TIMER_H + + +#include +#include "hip_macros.h" +#include "hip_device.h" + +namespace ucl_hip { + +/// Class for timing CUDA Driver events +class UCL_Timer { + public: + inline UCL_Timer() : _total_time(0.0f), _initialized(false) { } + inline UCL_Timer(UCL_Device &dev) : _total_time(0.0f), _initialized(false) + { init(dev); } + + inline ~UCL_Timer() { clear(); } + + /// Clear any data associated with timer + /** \note init() must be called to reuse timer after a clear() **/ + inline void clear() { + if (_initialized) { + CU_DESTRUCT_CALL(hipEventDestroy(start_event)); + CU_DESTRUCT_CALL(hipEventDestroy(stop_event)); + _initialized=false; + _total_time=0.0; + } + } + + /// Initialize default command queue for timing + inline void init(UCL_Device &dev) { init(dev, dev.cq()); } + + /// Initialize command queue for timing + inline void init(UCL_Device &dev, command_queue &cq) { + clear(); + _cq=cq; + _initialized=true; + CU_SAFE_CALL( hipEventCreateWithFlags(&start_event,0) ); + CU_SAFE_CALL( hipEventCreateWithFlags(&stop_event,0) ); + } + + /// Start timing on command queue + inline void start() { CU_SAFE_CALL(hipEventRecord(start_event,_cq)); } + + /// Stop timing on command queue + inline void stop() { CU_SAFE_CALL(hipEventRecord(stop_event,_cq)); } + + /// Block until the start event has been reached on device + inline void sync_start() + { CU_SAFE_CALL(hipEventSynchronize(start_event)); } + + /// Block until the stop event has been reached on device + inline void sync_stop() + { CU_SAFE_CALL(hipEventSynchronize(stop_event)); } + + /// Set the time elapsed to zero (not the total_time) + inline void zero() { + CU_SAFE_CALL(hipEventRecord(start_event,_cq)); + CU_SAFE_CALL(hipEventRecord(stop_event,_cq)); + } + + /// Set the total time to zero + inline void zero_total() { _total_time=0.0; } + + /// Add time from previous start and stop to total + /** Forces synchronization **/ + inline double add_to_total() + { double t=time(); _total_time+=t; return t/1000.0; } + + /// Add a user specified time to the total (ms) + inline void add_time_to_total(const double t) { _total_time+=t; } + + /// Return the time (ms) of last start to stop - Forces synchronization + inline double time() { + float timer; + CU_SAFE_CALL(hipEventSynchronize(stop_event)); + CU_SAFE_CALL( hipEventElapsedTime(&timer,start_event,stop_event) ); + return timer; + } + + /// Return the time (s) of last start to stop - Forces synchronization + inline double seconds() { return time()/1000.0; } + + /// Return the total time in ms + inline double total_time() { return _total_time; } + + /// Return the total time in seconds + inline double total_seconds() { return _total_time/1000.0; } + + private: + hipEvent_t start_event, stop_event; + hipStream_t _cq; + double _total_time; + bool _initialized; +}; + +} // namespace + +#endif diff --git a/lib/gpu/geryon/ucl_get_devices.cpp b/lib/gpu/geryon/ucl_get_devices.cpp index 1fa758fb46..b8dfc6f7b1 100644 --- a/lib/gpu/geryon/ucl_get_devices.cpp +++ b/lib/gpu/geryon/ucl_get_devices.cpp @@ -36,6 +36,11 @@ using namespace ucl_cudadr; using namespace ucl_cudart; #endif +#ifdef UCL_HIP +#include "hip_device.h" +using namespace ucl_hip; +#endif + int main(int argc, char** argv) { UCL_Device cop; std::cout << "Found " << cop.num_platforms() << " platform(s).\n"; diff --git a/lib/gpu/lal_answer.cpp b/lib/gpu/lal_answer.cpp index aa6d33d334..95d40c0d0a 100644 --- a/lib/gpu/lal_answer.cpp +++ b/lib/gpu/lal_answer.cpp @@ -179,13 +179,15 @@ double AnswerT::energy_virial(double *eatom, double **vatom, if (_eflag) { for (int i=0; i<_inum; i++) evdwl+=engv[i]; - if (_ef_atom) - if (_ilist==NULL) + if (_ef_atom) { + if (_ilist==NULL) { for (int i=0; i<_inum; i++) eatom[i]+=engv[i]; - else + } else { for (int i=0; i<_inum; i++) eatom[_ilist[i]]+=engv[i]; + } + } vstart=_inum; } if (_vflag) { @@ -193,7 +195,7 @@ double AnswerT::energy_virial(double *eatom, double **vatom, for (int j=0; j<6; j++) { for (int i=vstart; i +#include +#endif + namespace LAMMPS_AL { #define AtomT Atom @@ -70,6 +75,26 @@ bool AtomT::alloc(const int nall) { } #endif + #ifdef USE_HIP_DEVICE_SORT + if (_gpu_nbor==1) { + size_t temp_storage_bytes = 0; + if(hipSuccess != hipcub::DeviceRadixSort::SortPairs(nullptr, temp_storage_bytes, sort_out_keys, sort_out_keys, sort_out_values, sort_out_values, _max_atoms)) + return false; + if(sort_out_size < _max_atoms){ + if (sort_out_keys ) hipFree(sort_out_keys); + if (sort_out_values) hipFree(sort_out_values); + hipMalloc(&sort_out_keys , _max_atoms * sizeof(unsigned)); + hipMalloc(&sort_out_values, _max_atoms * sizeof(int )); + sort_out_size = _max_atoms; + } + if(temp_storage_bytes > sort_temp_storage_size){ + if(sort_temp_storage) hipFree(sort_temp_storage); + hipMalloc(&sort_temp_storage, temp_storage_bytes); + sort_temp_storage_size = temp_storage_bytes; + } + } + #endif + // --------------------------- Device allocations int gpu_bytes=0; success=success && (x.alloc(_max_atoms*4,*dev,UCL_WRITE_ONLY, @@ -184,6 +209,27 @@ bool AtomT::add_fields(const bool charge, const bool rot, return false; } #endif + + #ifdef USE_HIP_DEVICE_SORT + if (_gpu_nbor==1) { + size_t temp_storage_bytes = 0; + if(hipSuccess != hipcub::DeviceRadixSort::SortPairs(nullptr, temp_storage_bytes, sort_out_keys, sort_out_keys, sort_out_values, sort_out_values, _max_atoms)) + return false; + if(sort_out_size < _max_atoms){ + if (sort_out_keys ) hipFree(sort_out_keys); + if (sort_out_values) hipFree(sort_out_values); + hipMalloc(&sort_out_keys , _max_atoms * sizeof(unsigned)); + hipMalloc(&sort_out_values, _max_atoms * sizeof(int )); + sort_out_size = _max_atoms; + } + if(temp_storage_bytes > sort_temp_storage_size){ + if(sort_temp_storage) hipFree(sort_temp_storage); + hipMalloc(&sort_temp_storage, temp_storage_bytes); + sort_temp_storage_size = temp_storage_bytes; + } + } + #endif + success=success && (dev_particle_id.alloc(_max_atoms,*dev, UCL_READ_ONLY)==UCL_SUCCESS); gpu_bytes+=dev_particle_id.row_bytes(); @@ -275,6 +321,19 @@ void AtomT::clear_resize() { if (_gpu_nbor==1) cudppDestroyPlan(sort_plan); #endif + #ifdef USE_HIP_DEVICE_SORT + if (_gpu_nbor==1) { + if(sort_out_keys) hipFree(sort_out_keys); + if(sort_out_values) hipFree(sort_out_values); + if(sort_temp_storage) hipFree(sort_temp_storage); + sort_out_keys = nullptr; + sort_out_values = nullptr; + sort_temp_storage = nullptr; + sort_temp_storage_size = 0; + sort_out_size = 0; + } + #endif + if (_gpu_nbor==2) { host_particle_id.clear(); host_cell_id.clear(); @@ -326,6 +385,22 @@ void AtomT::sort_neighbor(const int num_atoms) { UCL_GERYON_EXIT; } #endif + + #ifdef USE_HIP_DEVICE_SORT + if(sort_out_size < num_atoms){ + printf("AtomT::sort_neighbor: invalid temp buffer size\n"); + UCL_GERYON_EXIT; + } + if(hipSuccess != hipcub::DeviceRadixSort::SortPairs(sort_temp_storage, sort_temp_storage_size, (unsigned *)dev_cell_id.begin(), sort_out_keys, (int *)dev_particle_id.begin(), sort_out_values, num_atoms)){ + printf("AtomT::sort_neighbor: DeviceRadixSort error\n"); + UCL_GERYON_EXIT; + } + if(hipSuccess != hipMemcpy((unsigned *)dev_cell_id.begin(), sort_out_keys , num_atoms*sizeof(unsigned), hipMemcpyDeviceToDevice) || + hipSuccess != hipMemcpy((int *) dev_particle_id.begin(), sort_out_values, num_atoms*sizeof(int ), hipMemcpyDeviceToDevice)){ + printf("AtomT::sort_neighbor: copy output error\n"); + UCL_GERYON_EXIT; + } + #endif } #ifdef GPU_CAST diff --git a/lib/gpu/lal_atom.cu b/lib/gpu/lal_atom.cu index 28ff31c566..99c76ba625 100644 --- a/lib/gpu/lal_atom.cu +++ b/lib/gpu/lal_atom.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #endif diff --git a/lib/gpu/lal_atom.h b/lib/gpu/lal_atom.h index 57880d7ca9..e39740d6c8 100644 --- a/lib/gpu/lal_atom.h +++ b/lib/gpu/lal_atom.h @@ -29,6 +29,11 @@ using namespace ucl_opencl; #include "geryon/nvc_mat.h" #include "geryon/nvc_kernel.h" using namespace ucl_cudart; +#elif defined(USE_HIP) +#include "geryon/hip_timer.h" +#include "geryon/hip_mat.h" +#include "geryon/hip_kernel.h" +using namespace ucl_hip; #else #include "geryon/nvd_timer.h" #include "geryon/nvd_mat.h" @@ -477,6 +482,14 @@ class Atom { CUDPPConfiguration sort_config; CUDPPHandle sort_plan; #endif + + #ifdef USE_HIP_DEVICE_SORT + unsigned* sort_out_keys = nullptr; + int* sort_out_values = nullptr; + void* sort_temp_storage = nullptr; + size_t sort_temp_storage_size = 0; + size_t sort_out_size = 0; + #endif }; } diff --git a/lib/gpu/lal_aux_fun1.h b/lib/gpu/lal_aux_fun1.h index 47a216ff6f..5b7150d950 100644 --- a/lib/gpu/lal_aux_fun1.h +++ b/lib/gpu/lal_aux_fun1.h @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #endif diff --git a/lib/gpu/lal_base_atomic.h b/lib/gpu/lal_base_atomic.h index e3e9829abc..fef810b17b 100644 --- a/lib/gpu/lal_base_atomic.h +++ b/lib/gpu/lal_base_atomic.h @@ -24,6 +24,8 @@ #include "geryon/ocl_texture.h" #elif defined(USE_CUDART) #include "geryon/nvc_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_base_charge.h b/lib/gpu/lal_base_charge.h index 64c19554b9..ea81dcdc4e 100644 --- a/lib/gpu/lal_base_charge.h +++ b/lib/gpu/lal_base_charge.h @@ -25,6 +25,8 @@ #include "geryon/ocl_texture.h" #elif defined(USE_CUDART) #include "geryon/nvc_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_base_dipole.h b/lib/gpu/lal_base_dipole.h index b51c4303cf..31a2a2d5f7 100644 --- a/lib/gpu/lal_base_dipole.h +++ b/lib/gpu/lal_base_dipole.h @@ -23,6 +23,8 @@ #ifdef USE_OPENCL #include "geryon/ocl_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_base_dpd.h b/lib/gpu/lal_base_dpd.h index 7a75282d0a..1e6f2ab1f2 100644 --- a/lib/gpu/lal_base_dpd.h +++ b/lib/gpu/lal_base_dpd.h @@ -23,6 +23,8 @@ #ifdef USE_OPENCL #include "geryon/ocl_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_base_ellipsoid.h b/lib/gpu/lal_base_ellipsoid.h index 7deeccbf44..061baac5b6 100644 --- a/lib/gpu/lal_base_ellipsoid.h +++ b/lib/gpu/lal_base_ellipsoid.h @@ -24,6 +24,8 @@ #include "geryon/ocl_texture.h" #elif defined(USE_CUDART) #include "geryon/nvc_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_base_three.h b/lib/gpu/lal_base_three.h index f5f36863c4..75589f705d 100644 --- a/lib/gpu/lal_base_three.h +++ b/lib/gpu/lal_base_three.h @@ -24,6 +24,8 @@ #include "geryon/ocl_texture.h" #elif defined(USE_CUDART) #include "geryon/nvc_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_beck.cu b/lib/gpu/lal_beck.cu index 7d72128b5f..bdfa57a0ce 100644 --- a/lib/gpu/lal_beck.cu +++ b/lib/gpu/lal_beck.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_born.cu b/lib/gpu/lal_born.cu index 0ca7fea5fe..6e1d7d95a0 100644 --- a/lib/gpu/lal_born.cu +++ b/lib/gpu/lal_born.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_born_coul_long.cu b/lib/gpu/lal_born_coul_long.cu index 71e5e0ae50..441ce4beb5 100644 --- a/lib/gpu/lal_born_coul_long.cu +++ b/lib/gpu/lal_born_coul_long.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_born_coul_long_cs.cu b/lib/gpu/lal_born_coul_long_cs.cu index b3e79d9ec8..f4b6da2d0d 100644 --- a/lib/gpu/lal_born_coul_long_cs.cu +++ b/lib/gpu/lal_born_coul_long_cs.cu @@ -13,15 +13,16 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" + #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_born_coul_wolf.cu b/lib/gpu/lal_born_coul_wolf.cu index 2c2249feeb..e34367e18b 100644 --- a/lib/gpu/lal_born_coul_wolf.cu +++ b/lib/gpu/lal_born_coul_wolf.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_born_coul_wolf_cs.cu b/lib/gpu/lal_born_coul_wolf_cs.cu index 847387bfe8..1a02420736 100644 --- a/lib/gpu/lal_born_coul_wolf_cs.cu +++ b/lib/gpu/lal_born_coul_wolf_cs.cu @@ -13,15 +13,15 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_buck.cu b/lib/gpu/lal_buck.cu index c1e1c7d7e2..c23186f2d8 100644 --- a/lib/gpu/lal_buck.cu +++ b/lib/gpu/lal_buck.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_buck_coul.cu b/lib/gpu/lal_buck_coul.cu index 6f0d414825..2282532f4a 100644 --- a/lib/gpu/lal_buck_coul.cu +++ b/lib/gpu/lal_buck_coul.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_buck_coul_long.cu b/lib/gpu/lal_buck_coul_long.cu index da3237a31f..469c235571 100644 --- a/lib/gpu/lal_buck_coul_long.cu +++ b/lib/gpu/lal_buck_coul_long.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_charmm_long.cu b/lib/gpu/lal_charmm_long.cu index 244131f833..a797707057 100644 --- a/lib/gpu/lal_charmm_long.cu +++ b/lib/gpu/lal_charmm_long.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_colloid.cu b/lib/gpu/lal_colloid.cu index 28a9809b19..437faff25b 100644 --- a/lib/gpu/lal_colloid.cu +++ b/lib/gpu/lal_colloid.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_coul.cu b/lib/gpu/lal_coul.cu index 503e674c81..21d849bb6f 100644 --- a/lib/gpu/lal_coul.cu +++ b/lib/gpu/lal_coul.cu @@ -13,15 +13,15 @@ // email : ndtrung@umich.edu // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_coul_debye.cu b/lib/gpu/lal_coul_debye.cu index 464a1b18de..ab8bc5b961 100644 --- a/lib/gpu/lal_coul_debye.cu +++ b/lib/gpu/lal_coul_debye.cu @@ -13,15 +13,15 @@ // email : ndtrung@umich.edu // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_coul_dsf.cu b/lib/gpu/lal_coul_dsf.cu index 82c44cd382..147ac68552 100644 --- a/lib/gpu/lal_coul_dsf.cu +++ b/lib/gpu/lal_coul_dsf.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_coul_long.cu b/lib/gpu/lal_coul_long.cu index 365195e00c..f97a039629 100644 --- a/lib/gpu/lal_coul_long.cu +++ b/lib/gpu/lal_coul_long.cu @@ -13,15 +13,15 @@ // email : a.kohlmeyer@temple.edu // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_coul_long_cs.cu b/lib/gpu/lal_coul_long_cs.cu index 3c34666131..1479157944 100644 --- a/lib/gpu/lal_coul_long_cs.cu +++ b/lib/gpu/lal_coul_long_cs.cu @@ -13,15 +13,15 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_device.cpp b/lib/gpu/lal_device.cpp index 5bd306ea5b..aaf74ed28c 100644 --- a/lib/gpu/lal_device.cpp +++ b/lib/gpu/lal_device.cpp @@ -268,7 +268,7 @@ int DeviceT::init(Answer &ans, const bool charge, gpu_nbor=1; else if (_gpu_mode==Device::GPU_HYB_NEIGH) gpu_nbor=2; - #ifndef USE_CUDPP + #if !defined(USE_CUDPP) && !defined(USE_HIP_DEVICE_SORT) if (gpu_nbor==1) gpu_nbor=2; #endif @@ -341,7 +341,7 @@ int DeviceT::init_nbor(Neighbor *nbor, const int nlocal, gpu_nbor=1; else if (_gpu_mode==Device::GPU_HYB_NEIGH) gpu_nbor=2; - #ifndef USE_CUDPP + #if !defined(USE_CUDPP) && !defined(USE_HIP_DEVICE_SORT) if (gpu_nbor==1) gpu_nbor=2; #endif @@ -712,7 +712,7 @@ int DeviceT::compile_kernels() { gpu_lib_data.update_host(false); _ptx_arch=static_cast(gpu_lib_data[0])/100.0; - #ifndef USE_OPENCL + #if !(defined(USE_OPENCL) || defined(USE_HIP)) if (_ptx_arch>gpu->arch() || floor(_ptx_arch)arch())) return -4; #endif diff --git a/lib/gpu/lal_device.cu b/lib/gpu/lal_device.cu index 37d0758845..afc7a0b988 100644 --- a/lib/gpu/lal_device.cu +++ b/lib/gpu/lal_device.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // *************************************************************************** -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #endif diff --git a/lib/gpu/lal_dipole_lj.cu b/lib/gpu/lal_dipole_lj.cu index 745bdb7f27..8ea49e7f60 100644 --- a/lib/gpu/lal_dipole_lj.cu +++ b/lib/gpu/lal_dipole_lj.cu @@ -13,16 +13,16 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; -texture mu_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); +_texture( mu_tex,float4); #else -texture pos_tex; -texture q_tex; -texture mu_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); +_texture_2d( mu_tex,int4); #endif #else diff --git a/lib/gpu/lal_dipole_lj_sf.cu b/lib/gpu/lal_dipole_lj_sf.cu index 9847e84823..9d753d9b63 100644 --- a/lib/gpu/lal_dipole_lj_sf.cu +++ b/lib/gpu/lal_dipole_lj_sf.cu @@ -13,17 +13,17 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; -texture mu_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); +_texture( mu_tex,float4); #else -texture pos_tex; -texture q_tex; -texture mu_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); +_texture_2d( mu_tex,int4); #endif #else diff --git a/lib/gpu/lal_dipole_long_lj.cu b/lib/gpu/lal_dipole_long_lj.cu index f888dece9b..95c3b7a3db 100644 --- a/lib/gpu/lal_dipole_long_lj.cu +++ b/lib/gpu/lal_dipole_long_lj.cu @@ -13,16 +13,16 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; -texture mu_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); +_texture( mu_tex,float4); #else -texture pos_tex; -texture q_tex; -texture mu_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); +_texture_2d( mu_tex,int4); #endif #else diff --git a/lib/gpu/lal_dpd.cu b/lib/gpu/lal_dpd.cu index 462401ad70..d97f430f77 100644 --- a/lib/gpu/lal_dpd.cu +++ b/lib/gpu/lal_dpd.cu @@ -13,14 +13,14 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture vel_tex; +_texture( pos_tex,float4); +_texture( vel_tex,float4); #else -texture pos_tex; -texture vel_tex; +_texture_2d( pos_tex,int4); +_texture_2d( vel_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_eam.cu b/lib/gpu/lal_eam.cu index 13440b7d45..9427b1832f 100644 --- a/lib/gpu/lal_eam.cu +++ b/lib/gpu/lal_eam.cu @@ -13,27 +13,27 @@ // email : brownw@ornl.gov nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture fp_tex; -texture rhor_sp1_tex; -texture rhor_sp2_tex; -texture frho_sp1_tex; -texture frho_sp2_tex; -texture z2r_sp1_tex; -texture z2r_sp2_tex; +_texture( pos_tex,float4); +_texture( fp_tex,float); +_texture( rhor_sp1_tex,float4); +_texture( rhor_sp2_tex,float4); +_texture( frho_sp1_tex,float4); +_texture( frho_sp2_tex,float4); +_texture( z2r_sp1_tex,float4); +_texture( z2r_sp2_tex,float4); #else -texture pos_tex; -texture fp_tex; -texture rhor_sp1_tex; -texture rhor_sp2_tex; -texture frho_sp1_tex; -texture frho_sp2_tex; -texture z2r_sp1_tex; -texture z2r_sp2_tex; +_texture( pos_tex,int4); +_texture( fp_tex,int2); +_texture( rhor_sp1_tex,int4); +_texture( rhor_sp2_tex,int4); +_texture( frho_sp1_tex,int4); +_texture( frho_sp2_tex,int4); +_texture( z2r_sp1_tex,int4); +_texture( z2r_sp2_tex,int4); #endif #else diff --git a/lib/gpu/lal_ellipsoid_extra.h b/lib/gpu/lal_ellipsoid_extra.h index 71668f5e02..e6122c7404 100644 --- a/lib/gpu/lal_ellipsoid_extra.h +++ b/lib/gpu/lal_ellipsoid_extra.h @@ -18,12 +18,14 @@ enum{SPHERE_SPHERE,SPHERE_ELLIPSE,ELLIPSE_SPHERE,ELLIPSE_ELLIPSE}; -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex, quat_tex; +_texture( pos_tex, float4); +_texture( quat_tex,float4); #else -texture pos_tex, quat_tex; +_texture_2d( pos_tex,int4); +_texture_2d( quat_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_ellipsoid_nbor.cu b/lib/gpu/lal_ellipsoid_nbor.cu index cac77f5dd3..e6eedc7159 100644 --- a/lib/gpu/lal_ellipsoid_nbor.cu +++ b/lib/gpu/lal_ellipsoid_nbor.cu @@ -13,12 +13,12 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_gauss.cu b/lib/gpu/lal_gauss.cu index 98e71ea413..f9d3741537 100644 --- a/lib/gpu/lal_gauss.cu +++ b/lib/gpu/lal_gauss.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_gayberne.cu b/lib/gpu/lal_gayberne.cu index cd1ee59fc6..5c035da004 100644 --- a/lib/gpu/lal_gayberne.cu +++ b/lib/gpu/lal_gayberne.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_ellipsoid_extra.h" #endif diff --git a/lib/gpu/lal_gayberne_lj.cu b/lib/gpu/lal_gayberne_lj.cu index 7925b72784..eb9c797dc7 100644 --- a/lib/gpu/lal_gayberne_lj.cu +++ b/lib/gpu/lal_gayberne_lj.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_ellipsoid_extra.h" #endif diff --git a/lib/gpu/lal_lj.cu b/lib/gpu/lal_lj.cu index 5838ac95cf..716346a83d 100644 --- a/lib/gpu/lal_lj.cu +++ b/lib/gpu/lal_lj.cu @@ -13,12 +13,12 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_lj96.cu b/lib/gpu/lal_lj96.cu index 8dd63ef920..aa06caa4ae 100644 --- a/lib/gpu/lal_lj96.cu +++ b/lib/gpu/lal_lj96.cu @@ -13,12 +13,12 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_lj_class2_long.cu b/lib/gpu/lal_lj_class2_long.cu index 41ceca35d7..4e1bf9c1f7 100644 --- a/lib/gpu/lal_lj_class2_long.cu +++ b/lib/gpu/lal_lj_class2_long.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_coul.cu b/lib/gpu/lal_lj_coul.cu index 5c7f0da46f..cd72f72d97 100644 --- a/lib/gpu/lal_lj_coul.cu +++ b/lib/gpu/lal_lj_coul.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_coul_debye.cu b/lib/gpu/lal_lj_coul_debye.cu index 91b105b3da..40b7046623 100644 --- a/lib/gpu/lal_lj_coul_debye.cu +++ b/lib/gpu/lal_lj_coul_debye.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_coul_long.cu b/lib/gpu/lal_lj_coul_long.cu index 0e25bb2dbc..6a09cc4b75 100644 --- a/lib/gpu/lal_lj_coul_long.cu +++ b/lib/gpu/lal_lj_coul_long.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_coul_msm.cu b/lib/gpu/lal_lj_coul_msm.cu index 3f73c6f47d..c8eaa47b3d 100644 --- a/lib/gpu/lal_lj_coul_msm.cu +++ b/lib/gpu/lal_lj_coul_msm.cu @@ -13,19 +13,19 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; -texture gcons_tex; -texture dgcons_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); +_texture( gcons_tex,float); +_texture( dgcons_tex,float); #else -texture pos_tex; -texture q_tex; -texture gcons_tex; -texture dgcons_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); +_texture( gcons_tex,int2); +_texture( dgcons_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_cubic.cu b/lib/gpu/lal_lj_cubic.cu index 683c6b2aac..b6a0768a36 100644 --- a/lib/gpu/lal_lj_cubic.cu +++ b/lib/gpu/lal_lj_cubic.cu @@ -13,12 +13,12 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_lj_dsf.cu b/lib/gpu/lal_lj_dsf.cu index 323576fe77..2475743ccc 100644 --- a/lib/gpu/lal_lj_dsf.cu +++ b/lib/gpu/lal_lj_dsf.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_expand.cu b/lib/gpu/lal_lj_expand.cu index 9281ad27bd..4496835588 100644 --- a/lib/gpu/lal_lj_expand.cu +++ b/lib/gpu/lal_lj_expand.cu @@ -13,13 +13,13 @@ // email : ibains@nvidia.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else diff --git a/lib/gpu/lal_lj_expand_coul_long.cu b/lib/gpu/lal_lj_expand_coul_long.cu index aa8f02be8c..e9de9bab27 100644 --- a/lib/gpu/lal_lj_expand_coul_long.cu +++ b/lib/gpu/lal_lj_expand_coul_long.cu @@ -13,15 +13,15 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_gromacs.cu b/lib/gpu/lal_lj_gromacs.cu index 93dc3d9456..dcef79dc90 100644 --- a/lib/gpu/lal_lj_gromacs.cu +++ b/lib/gpu/lal_lj_gromacs.cu @@ -13,13 +13,13 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else diff --git a/lib/gpu/lal_lj_sdk.cu b/lib/gpu/lal_lj_sdk.cu index 01b2cdd18d..a11b1c7887 100644 --- a/lib/gpu/lal_lj_sdk.cu +++ b/lib/gpu/lal_lj_sdk.cu @@ -13,12 +13,12 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_lj_sdk_long.cu b/lib/gpu/lal_lj_sdk_long.cu index 5ff64b2254..e28fa19db4 100644 --- a/lib/gpu/lal_lj_sdk_long.cu +++ b/lib/gpu/lal_lj_sdk_long.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_lj_tip4p_long.cpp b/lib/gpu/lal_lj_tip4p_long.cpp index d44edc8cbd..0b781300c7 100644 --- a/lib/gpu/lal_lj_tip4p_long.cpp +++ b/lib/gpu/lal_lj_tip4p_long.cpp @@ -23,7 +23,7 @@ const char *lj_tip4p=0; #include "lal_lj_tip4p_long.h" #include -using namespace LAMMPS_AL; +namespace LAMMPS_AL { #define LJTIP4PLongT LJ_TIP4PLong extern Device device; @@ -370,6 +370,5 @@ int** LJTIP4PLongT::compute(const int ago, const int inum_full, } - - template class LJ_TIP4PLong; +} diff --git a/lib/gpu/lal_lj_tip4p_long.cu b/lib/gpu/lal_lj_tip4p_long.cu index 147c460795..092513da4d 100644 --- a/lib/gpu/lal_lj_tip4p_long.cu +++ b/lib/gpu/lal_lj_tip4p_long.cu @@ -13,7 +13,7 @@ // email : thevsevak@gmail.com // *************************************************************************** -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifdef LAMMPS_SMALLBIG @@ -27,11 +27,11 @@ #define tagint int #endif #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif #else diff --git a/lib/gpu/lal_mie.cu b/lib/gpu/lal_mie.cu index 33018566eb..e2ede4d3a1 100644 --- a/lib/gpu/lal_mie.cu +++ b/lib/gpu/lal_mie.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_morse.cu b/lib/gpu/lal_morse.cu index 0a14071d19..7e4e0e54fa 100644 --- a/lib/gpu/lal_morse.cu +++ b/lib/gpu/lal_morse.cu @@ -13,13 +13,13 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else diff --git a/lib/gpu/lal_neighbor_cpu.cu b/lib/gpu/lal_neighbor_cpu.cu index d005eb9f97..29141a8b90 100644 --- a/lib/gpu/lal_neighbor_cpu.cu +++ b/lib/gpu/lal_neighbor_cpu.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #endif diff --git a/lib/gpu/lal_neighbor_gpu.cu b/lib/gpu/lal_neighbor_gpu.cu index 83692a24e4..8a2b603217 100644 --- a/lib/gpu/lal_neighbor_gpu.cu +++ b/lib/gpu/lal_neighbor_gpu.cu @@ -14,7 +14,7 @@ // email : penwang@nvidia.com, brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #ifdef LAMMPS_SMALLBIG #define tagint int @@ -27,9 +27,9 @@ #define tagint int #endif #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif __kernel void calc_cell_id(const numtyp4 *restrict pos, diff --git a/lib/gpu/lal_neighbor_shared.h b/lib/gpu/lal_neighbor_shared.h index 834ee8406d..5cfc4e4767 100644 --- a/lib/gpu/lal_neighbor_shared.h +++ b/lib/gpu/lal_neighbor_shared.h @@ -24,6 +24,10 @@ using namespace ucl_opencl; #include "geryon/nvc_kernel.h" #include "geryon/nvc_texture.h" using namespace ucl_cudart; +#elif defined(USE_HIP) +#include "geryon/hip_kernel.h" +#include "geryon/hip_texture.h" +using namespace ucl_hip; #else #include "geryon/nvd_kernel.h" #include "geryon/nvd_texture.h" diff --git a/lib/gpu/lal_pppm.cu b/lib/gpu/lal_pppm.cu index 24636b9a93..6a7408c720 100644 --- a/lib/gpu/lal_pppm.cu +++ b/lib/gpu/lal_pppm.cu @@ -13,15 +13,15 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_preprocessor.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture q_tex; +_texture( pos_tex,float4); +_texture( q_tex,float); #else -texture pos_tex; -texture q_tex; +_texture_2d( pos_tex,int4); +_texture( q_tex,int2); #endif // Allow PPPM to compile without atomics for NVIDIA 1.0 cards, error diff --git a/lib/gpu/lal_pppm.h b/lib/gpu/lal_pppm.h index 045423e079..bc5f216076 100644 --- a/lib/gpu/lal_pppm.h +++ b/lib/gpu/lal_pppm.h @@ -23,6 +23,8 @@ #include "geryon/ocl_texture.h" #elif defined(USE_CUDART) #include "geryon/nvc_texture.h" +#elif defined(USE_HIP) +#include "geryon/hip_texture.h" #else #include "geryon/nvd_texture.h" #endif diff --git a/lib/gpu/lal_precision.h b/lib/gpu/lal_precision.h index d5b1b9b6c0..7f82ba18aa 100644 --- a/lib/gpu/lal_precision.h +++ b/lib/gpu/lal_precision.h @@ -24,9 +24,11 @@ struct _lgpu_int2 { int x; int y; }; +#ifndef USE_HIP #ifndef int2 #define int2 _lgpu_int2 #endif +#endif struct _lgpu_float2 { float x; float y; diff --git a/lib/gpu/lal_preprocessor.h b/lib/gpu/lal_preprocessor.h index 566a451c21..cd95355ee4 100644 --- a/lib/gpu/lal_preprocessor.h +++ b/lib/gpu/lal_preprocessor.h @@ -1,4 +1,4 @@ -// ************************************************************************** +// ************************************************************************** // preprocessor.cu // ------------------- // W. Michael Brown (ORNL) @@ -60,6 +60,150 @@ // //*************************************************************************/ +#define _texture(name, type) texture name +#define _texture_2d(name, type) texture name + +// ------------------------------------------------------------------------- +// HIP DEFINITIONS +// ------------------------------------------------------------------------- + +#ifdef USE_HIP + #include + #ifdef __HIP_PLATFORM_HCC__ + #define mul24(x, y) __mul24(x, y) + #undef _texture + #undef _texture_2d + #define _texture(name, type) __device__ type* name + #define _texture_2d(name, type) __device__ type* name + #endif + #define GLOBAL_ID_X threadIdx.x+mul24(blockIdx.x,blockDim.x) + #define GLOBAL_ID_Y threadIdx.y+mul24(blockIdx.y,blockDim.y) + #define GLOBAL_SIZE_X mul24(gridDim.x,blockDim.x); + #define GLOBAL_SIZE_Y mul24(gridDim.y,blockDim.y); + #define THREAD_ID_X threadIdx.x + #define THREAD_ID_Y threadIdx.y + #define BLOCK_ID_X blockIdx.x + #define BLOCK_ID_Y blockIdx.y + #define BLOCK_SIZE_X blockDim.x + #define BLOCK_SIZE_Y blockDim.y + #define __kernel extern "C" __global__ + #ifdef __local + #undef __local + #endif + #define __local __shared__ + #define __global + #define restrict __restrict__ + #define atom_add atomicAdd + #define ucl_inline static __inline__ __device__ + + #define THREADS_PER_ATOM 4 + #define THREADS_PER_CHARGE 8 + #define BLOCK_NBOR_BUILD 128 + #define BLOCK_PAIR 256 + #define BLOCK_BIO_PAIR 256 + #define BLOCK_ELLIPSE 128 + #define MAX_SHARED_TYPES 11 + + #ifdef _SINGLE_SINGLE + ucl_inline double shfl_xor(double var, int laneMask, int width) { + #ifdef __HIP_PLATFORM_HCC__ + return __shfl_xor(var, laneMask, width); + #else + return __shfl_xor_sync(0xffffffff, var, laneMask, width); + #endif + } + #else + ucl_inline double shfl_xor(double var, int laneMask, int width) { + int2 tmp; + tmp.x = __double2hiint(var); + tmp.y = __double2loint(var); + #ifdef __HIP_PLATFORM_HCC__ + tmp.x = __shfl_xor(tmp.x,laneMask,width); + tmp.y = __shfl_xor(tmp.y,laneMask,width); + #else + tmp.x = __shfl_xor_sync(0xffffffff, tmp.x,laneMask,width); + tmp.y = __shfl_xor_sync(0xffffffff, tmp.y,laneMask,width); + #endif + return __hiloint2double(tmp.x,tmp.y); + } + #endif + + #ifdef __HIP_PLATFORM_HCC__ + #define ARCH 600 + #define WARP_SIZE 64 + #endif + + #ifdef __HIP_PLATFORM_NVCC__ + #define ARCH __CUDA_ARCH__ + #define WARP_SIZE 32 + #endif + + #define fast_mul(X,Y) (X)*(Y) + + #define MEM_THREADS WARP_SIZE + #define PPPM_BLOCK_1D 64 + #define BLOCK_CELL_2D 8 + #define BLOCK_CELL_ID 128 + #define MAX_BIO_SHARED_TYPES 128 + + #ifdef __HIP_PLATFORM_NVCC__ + #ifdef _DOUBLE_DOUBLE + #define fetch4(ans,i,pos_tex) { \ + int4 xy = tex1Dfetch(pos_tex,i*2); \ + int4 zt = tex1Dfetch(pos_tex,i*2+1); \ + ans.x=__hiloint2double(xy.y, xy.x); \ + ans.y=__hiloint2double(xy.w, xy.z); \ + ans.z=__hiloint2double(zt.y, zt.x); \ + ans.w=__hiloint2double(zt.w, zt.z); \ + } + #define fetch(ans,i,q_tex) { \ + int2 qt = tex1Dfetch(q_tex,i); \ + ans=__hiloint2double(qt.y, qt.x); \ + } + #else + #define fetch4(ans,i,pos_tex) ans=tex1Dfetch(pos_tex, i); + #define fetch(ans,i,q_tex) ans=tex1Dfetch(q_tex,i); + #endif + #else + #ifdef _DOUBLE_DOUBLE + #define fetch4(ans,i,pos_tex) (ans=*(((double4*)pos_tex) + i)) + #define fetch(ans,i,q_tex) (ans=*(((double *) q_tex) + i)) + #else + #define fetch4(ans,i,pos_tex) (ans=*(((float4*)pos_tex) + i)) + #define fetch(ans,i,q_tex) (ans=*(((float *) q_tex) + i)) + #endif + #endif + + #ifdef _DOUBLE_DOUBLE + #define ucl_exp exp + #define ucl_powr pow + #define ucl_atan atan + #define ucl_cbrt cbrt + #define ucl_ceil ceil + #define ucl_abs fabs + #define ucl_rsqrt rsqrt + #define ucl_sqrt sqrt + #define ucl_recip(x) ((numtyp)1.0/(x)) + + #else + #define ucl_atan atanf + #define ucl_cbrt cbrtf + #define ucl_ceil ceilf + #define ucl_abs fabsf + #define ucl_recip(x) ((numtyp)1.0/(x)) + #define ucl_rsqrt rsqrtf + #define ucl_sqrt sqrtf + + #ifdef NO_HARDWARE_TRANSCENDENTALS + #define ucl_exp expf + #define ucl_powr powf + #else + #define ucl_exp __expf + #define ucl_powr __powf + #endif + #endif +#endif + // ------------------------------------------------------------------------- // CUDA DEFINITIONS // ------------------------------------------------------------------------- diff --git a/lib/gpu/lal_re_squared.cu b/lib/gpu/lal_re_squared.cu index e238734074..cd525a1ade 100644 --- a/lib/gpu/lal_re_squared.cu +++ b/lib/gpu/lal_re_squared.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_ellipsoid_extra.h" #endif diff --git a/lib/gpu/lal_re_squared_lj.cu b/lib/gpu/lal_re_squared_lj.cu index d69dae2461..b3c44febe7 100644 --- a/lib/gpu/lal_re_squared_lj.cu +++ b/lib/gpu/lal_re_squared_lj.cu @@ -13,7 +13,7 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_ellipsoid_extra.h" #endif diff --git a/lib/gpu/lal_soft.cu b/lib/gpu/lal_soft.cu index 831b986725..bccfa85ed5 100644 --- a/lib/gpu/lal_soft.cu +++ b/lib/gpu/lal_soft.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_sw.cu b/lib/gpu/lal_sw.cu index 3b6de5a683..de36d29efb 100644 --- a/lib/gpu/lal_sw.cu +++ b/lib/gpu/lal_sw.cu @@ -13,19 +13,19 @@ // email : brownw@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture sw1_tex; -texture sw2_tex; -texture sw3_tex; +_texture( pos_tex,float4); +_texture( sw1_tex,float4); +_texture( sw2_tex,float4); +_texture( sw3_tex,float4); #else -texture pos_tex; -texture sw1_tex; -texture sw2_tex; -texture sw3_tex; +_texture_2d( pos_tex,int4); +_texture( sw1_tex,int4); +_texture( sw2_tex,int4); +_texture( sw3_tex,int4); #endif #else diff --git a/lib/gpu/lal_table.cu b/lib/gpu/lal_table.cu index 971b56d96e..8c0b52e05f 100644 --- a/lib/gpu/lal_table.cu +++ b/lib/gpu/lal_table.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_tersoff.cu b/lib/gpu/lal_tersoff.cu index 2e29ca721b..d57efaf15c 100644 --- a/lib/gpu/lal_tersoff.cu +++ b/lib/gpu/lal_tersoff.cu @@ -13,23 +13,23 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_tersoff_extra.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture ts1_tex; -texture ts2_tex; -texture ts3_tex; -texture ts4_tex; -texture ts5_tex; +_texture( pos_tex,float4); +_texture( ts1_tex,float4); +_texture( ts2_tex,float4); +_texture( ts3_tex,float4); +_texture( ts4_tex,float4); +_texture( ts5_tex,float4); #else -texture pos_tex; -texture ts1_tex; -texture ts2_tex; -texture ts3_tex; -texture ts4_tex; -texture ts5_tex; +_texture_2d( pos_tex,int4); +_texture( ts1_tex,int4); +_texture( ts2_tex,int4); +_texture( ts3_tex,int4); +_texture( ts4_tex,int4); +_texture( ts5_tex,int4); #endif #else diff --git a/lib/gpu/lal_tersoff_extra.h b/lib/gpu/lal_tersoff_extra.h index 47d16678f0..7ee29751b7 100644 --- a/lib/gpu/lal_tersoff_extra.h +++ b/lib/gpu/lal_tersoff_extra.h @@ -16,7 +16,7 @@ #ifndef LAL_TERSOFF_EXTRA_H #define LAL_TERSOFF_EXTRA_H -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #else #endif diff --git a/lib/gpu/lal_tersoff_mod.cu b/lib/gpu/lal_tersoff_mod.cu index c85f5e08ca..da284f39ee 100644 --- a/lib/gpu/lal_tersoff_mod.cu +++ b/lib/gpu/lal_tersoff_mod.cu @@ -13,23 +13,23 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_tersoff_mod_extra.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture ts1_tex; -texture ts2_tex; -texture ts3_tex; -texture ts4_tex; -texture ts5_tex; +_texture( pos_tex,float4); +_texture( ts1_tex,float4); +_texture( ts2_tex,float4); +_texture( ts3_tex,float4); +_texture( ts4_tex,float4); +_texture( ts5_tex,float4); #else -texture pos_tex; -texture ts1_tex; -texture ts2_tex; -texture ts3_tex; -texture ts4_tex; -texture ts5_tex; +_texture_2d( pos_tex,int4); +_texture( ts1_tex,int4); +_texture( ts2_tex,int4); +_texture( ts3_tex,int4); +_texture( ts4_tex,int4); +_texture( ts5_tex,int4); #endif #else diff --git a/lib/gpu/lal_tersoff_mod_extra.h b/lib/gpu/lal_tersoff_mod_extra.h index a130d98488..fb658cb0da 100644 --- a/lib/gpu/lal_tersoff_mod_extra.h +++ b/lib/gpu/lal_tersoff_mod_extra.h @@ -16,7 +16,7 @@ #ifndef LAL_TERSOFF_MOD_EXTRA_H #define LAL_TERSOFF_MOD_EXTRA_H -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #else #endif diff --git a/lib/gpu/lal_tersoff_zbl.cu b/lib/gpu/lal_tersoff_zbl.cu index b574a529c0..a170715f57 100644 --- a/lib/gpu/lal_tersoff_zbl.cu +++ b/lib/gpu/lal_tersoff_zbl.cu @@ -13,25 +13,25 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_tersoff_zbl_extra.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture ts1_tex; -texture ts2_tex; -texture ts3_tex; -texture ts4_tex; -texture ts5_tex; -texture ts6_tex; +_texture( pos_tex,float4); +_texture( ts1_tex,float4); +_texture( ts2_tex,float4); +_texture( ts3_tex,float4); +_texture( ts4_tex,float4); +_texture( ts5_tex,float4); +_texture( ts6_tex,float4); #else -texture pos_tex; -texture ts1_tex; -texture ts2_tex; -texture ts3_tex; -texture ts4_tex; -texture ts5_tex; -texture ts6_tex; +_texture_2d( pos_tex,int4); +_texture( ts1_tex,int4); +_texture( ts2_tex,int4); +_texture( ts3_tex,int4); +_texture( ts4_tex,int4); +_texture( ts5_tex,int4); +_texture( ts6_tex,int4); #endif #else diff --git a/lib/gpu/lal_tersoff_zbl_extra.h b/lib/gpu/lal_tersoff_zbl_extra.h index 32c05a3716..9e5bcb10b4 100644 --- a/lib/gpu/lal_tersoff_zbl_extra.h +++ b/lib/gpu/lal_tersoff_zbl_extra.h @@ -16,7 +16,7 @@ #ifndef LAL_TERSOFF_ZBL_EXTRA_H #define LAL_TERSOFF_ZBL_EXTRA_H -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #else #endif diff --git a/lib/gpu/lal_ufm.cu b/lib/gpu/lal_ufm.cu index 51c4df3b5b..33d0f3c956 100644 --- a/lib/gpu/lal_ufm.cu +++ b/lib/gpu/lal_ufm.cu @@ -15,12 +15,12 @@ dekoning@ifi.unicamp.br ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_vashishta.cu b/lib/gpu/lal_vashishta.cu index 0da46c3b53..d13bc659e7 100644 --- a/lib/gpu/lal_vashishta.cu +++ b/lib/gpu/lal_vashishta.cu @@ -13,23 +13,23 @@ // email : andershaf@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture param1_tex; -texture param2_tex; -texture param3_tex; -texture param4_tex; -texture param5_tex; +_texture( pos_tex,float4); +_texture( param1_tex,float4); +_texture( param2_tex,float4); +_texture( param3_tex,float4); +_texture( param4_tex,float4); +_texture( param5_tex,float4); #else -texture pos_tex; -texture param1_tex; -texture param2_tex; -texture param3_tex; -texture param4_tex; -texture param5_tex; +_texture_2d( pos_tex,int4); +_texture( param1_tex,int4); +_texture( param2_tex,int4); +_texture( param3_tex,int4); +_texture( param4_tex,int4); +_texture( param5_tex,int4); #endif #else diff --git a/lib/gpu/lal_yukawa.cu b/lib/gpu/lal_yukawa.cu index a8d637ec97..5237549b0a 100644 --- a/lib/gpu/lal_yukawa.cu +++ b/lib/gpu/lal_yukawa.cu @@ -13,12 +13,12 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/lib/gpu/lal_yukawa_colloid.cu b/lib/gpu/lal_yukawa_colloid.cu index a3cbbbc11c..8c006a09be 100644 --- a/lib/gpu/lal_yukawa_colloid.cu +++ b/lib/gpu/lal_yukawa_colloid.cu @@ -13,15 +13,15 @@ // email : nguyentd@ornl.gov // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; -texture rad_tex; +_texture( pos_tex,float4); +_texture( rad_tex,float); #else -texture pos_tex; -texture rad_tex; +_texture_2d( pos_tex,int4); +_texture( rad_tex,int2); #endif #else diff --git a/lib/gpu/lal_zbl.cu b/lib/gpu/lal_zbl.cu index 33c850e134..fbedfe2de2 100644 --- a/lib/gpu/lal_zbl.cu +++ b/lib/gpu/lal_zbl.cu @@ -13,12 +13,12 @@ // email : ndactrung@gmail.com // ***************************************************************************/ -#ifdef NV_KERNEL +#if defined(NV_KERNEL) || defined(USE_HIP) #include "lal_aux_fun1.h" #ifndef _DOUBLE_DOUBLE -texture pos_tex; +_texture( pos_tex,float4); #else -texture pos_tex; +_texture_2d( pos_tex,int4); #endif #else #define pos_tex x_ diff --git a/src/MAKE/OPTIONS/Makefile.hip b/src/MAKE/OPTIONS/Makefile.hip new file mode 100644 index 0000000000..12158a32cb --- /dev/null +++ b/src/MAKE/OPTIONS/Makefile.hip @@ -0,0 +1,120 @@ +# hip = MPI with HIP(clang) + +SHELL = /bin/sh + +# --------------------------------------------------------------------- +# compiler/linker settings +# specify flags and libraries needed for your compiler + +CC = mpicxx +CCFLAGS = -g -O3 +SHFLAGS = -fPIC +DEPFLAGS = -M + +HIP_PATH ?= $(wildcard /opt/rocm/hip) +LINK = $(HIP_PATH)/bin/hipcc +LINKFLAGS = -g -O3 $(shell mpicxx --showme:link) +LIB = +SIZE = size + +ARCHIVE = ar +ARFLAGS = -rc +SHLIBFLAGS = -shared + +# --------------------------------------------------------------------- +# LAMMPS-specific settings, all OPTIONAL +# specify settings for LAMMPS features you will use +# if you change any -D setting, do full re-compile after "make clean" + +# LAMMPS ifdef settings +# see possible settings in Section 2.2 (step 4) of manual + +LMP_INC = -DLAMMPS_GZIP -DLAMMPS_MEMALIGN=64 + +# MPI library +# see discussion in Section 2.2 (step 5) of manual +# MPI wrapper compiler/linker can provide this info +# can point to dummy MPI library in src/STUBS as in Makefile.serial +# use -D MPICH and OMPI settings in INC to avoid C++ lib conflicts +# INC = path for mpi.h, MPI compiler settings +# PATH = path for MPI library +# LIB = name of MPI library + +MPI_INC = -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1 +MPI_PATH = +MPI_LIB = + +# FFT library +# see discussion in Section 2.2 (step 6) of manual +# can be left blank to use provided KISS FFT library +# INC = -DFFT setting, e.g. -DFFT_FFTW, FFT compiler settings +# PATH = path for FFT library +# LIB = name of FFT library + +FFT_INC = +FFT_PATH = +FFT_LIB = + +# JPEG and/or PNG library +# see discussion in Section 2.2 (step 7) of manual +# only needed if -DLAMMPS_JPEG or -DLAMMPS_PNG listed with LMP_INC +# INC = path(s) for jpeglib.h and/or png.h +# PATH = path(s) for JPEG library and/or PNG library +# LIB = name(s) of JPEG library and/or PNG library + +JPG_INC = +JPG_PATH = +JPG_LIB = + +# --------------------------------------------------------------------- +# build rules and dependencies +# do not edit this section + +include Makefile.package.settings +include Makefile.package + +ifeq (nvcc,${HIP_PLATFORM}) + # fix nvcc can't handle -pthread flag + LINKFLAGS := $(subst -pthread,-Xcompiler -pthread,$(LINKFLAGS)) +endif + +EXTRA_INC = $(LMP_INC) $(PKG_INC) $(MPI_INC) $(FFT_INC) $(JPG_INC) $(PKG_SYSINC) +EXTRA_PATH = $(PKG_PATH) $(MPI_PATH) $(FFT_PATH) $(JPG_PATH) $(PKG_SYSPATH) +EXTRA_LIB = $(PKG_LIB) $(MPI_LIB) $(FFT_LIB) $(JPG_LIB) $(PKG_SYSLIB) +EXTRA_CPP_DEPENDS = $(PKG_CPP_DEPENDS) +EXTRA_LINK_DEPENDS = $(PKG_LINK_DEPENDS) + +# Path to src files + +vpath %.cpp .. +vpath %.h .. + +# Link target + +$(EXE): $(OBJ) $(EXTRA_LINK_DEPENDS) + $(LINK) $(LINKFLAGS) $(EXTRA_PATH) $(OBJ) $(EXTRA_LIB) $(LIB) -o $(EXE) + $(SIZE) $(EXE) + +# Library targets + +lib: $(OBJ) $(EXTRA_LINK_DEPENDS) + $(ARCHIVE) $(ARFLAGS) $(EXE) $(OBJ) + +shlib: $(OBJ) $(EXTRA_LINK_DEPENDS) + $(CC) $(CCFLAGS) $(SHFLAGS) $(SHLIBFLAGS) $(EXTRA_PATH) -o $(EXE) \ + $(OBJ) $(EXTRA_LIB) $(LIB) + +# Compilation rules + +%.o:%.cpp + $(CC) $(CCFLAGS) $(SHFLAGS) $(EXTRA_INC) -c $< + +# Individual dependencies + +depend : fastdep.exe $(SRC) + @./fastdep.exe $(EXTRA_INC) -- $^ > .depend || exit 1 + +fastdep.exe: ../DEPEND/fastdep.c + cc -O -o $@ $< + +sinclude .depend -- GitLab From 44178a335e37dbe33d4a10988baedb15afd22424 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 29 Jan 2020 13:56:34 -0700 Subject: [PATCH 018/577] Propagate rename to Kokkos styles --- src/KOKKOS/atom_kokkos.cpp | 2 +- src/KOKKOS/atom_vec_angle_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_angle_kokkos.h | 2 +- src/KOKKOS/atom_vec_atomic_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_atomic_kokkos.h | 2 +- src/KOKKOS/atom_vec_bond_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_bond_kokkos.h | 2 +- src/KOKKOS/atom_vec_charge_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_charge_kokkos.h | 2 +- src/KOKKOS/atom_vec_dpd_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_dpd_kokkos.h | 2 +- src/KOKKOS/atom_vec_full_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_full_kokkos.h | 2 +- src/KOKKOS/atom_vec_hybrid_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_hybrid_kokkos.h | 2 +- src/KOKKOS/atom_vec_molecular_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_molecular_kokkos.h | 2 +- src/KOKKOS/atom_vec_sphere_kokkos.cpp | 4 ++-- src/KOKKOS/atom_vec_sphere_kokkos.h | 2 +- 19 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/KOKKOS/atom_kokkos.cpp b/src/KOKKOS/atom_kokkos.cpp index 4637a9a21c..49fdbb95bb 100644 --- a/src/KOKKOS/atom_kokkos.cpp +++ b/src/KOKKOS/atom_kokkos.cpp @@ -237,7 +237,7 @@ void AtomKokkos::grow(unsigned int mask){ sync(Device, mask); modified(Device, mask); memoryKK->grow_kokkos(k_special,special,nmax,maxspecial,"atom:special"); - avec->grow_reset(); + avec->grow_pointers(); sync(Host, mask); } } diff --git a/src/KOKKOS/atom_vec_angle_kokkos.cpp b/src/KOKKOS/atom_vec_angle_kokkos.cpp index 736e1c1fca..bbb5d2617d 100644 --- a/src/KOKKOS/atom_vec_angle_kokkos.cpp +++ b/src/KOKKOS/atom_vec_angle_kokkos.cpp @@ -98,7 +98,7 @@ void AtomVecAngleKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_angle_atom3,atomKK->angle_atom3,nmax,atomKK->angle_per_atom, "atom:angle_atom3"); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); if (atom->nextra_grow) @@ -110,7 +110,7 @@ void AtomVecAngleKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecAngleKokkos::grow_reset() +void AtomVecAngleKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_angle_kokkos.h b/src/KOKKOS/atom_vec_angle_kokkos.h index abdd48fce5..4fc71725b0 100644 --- a/src/KOKKOS/atom_vec_angle_kokkos.h +++ b/src/KOKKOS/atom_vec_angle_kokkos.h @@ -58,7 +58,7 @@ class AtomVecAngleKokkos : public AtomVecKokkos { int write_data_hybrid(FILE *, double *); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_comm_kokkos(const int &n, const DAT::tdual_int_2d &k_sendlist, const int & iswap, const DAT::tdual_xfloat_2d &buf, diff --git a/src/KOKKOS/atom_vec_atomic_kokkos.cpp b/src/KOKKOS/atom_vec_atomic_kokkos.cpp index 4fec5740d6..7b657fa0d1 100644 --- a/src/KOKKOS/atom_vec_atomic_kokkos.cpp +++ b/src/KOKKOS/atom_vec_atomic_kokkos.cpp @@ -74,7 +74,7 @@ void AtomVecAtomicKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); if (atom->nextra_grow) @@ -86,7 +86,7 @@ void AtomVecAtomicKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecAtomicKokkos::grow_reset() +void AtomVecAtomicKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_atomic_kokkos.h b/src/KOKKOS/atom_vec_atomic_kokkos.h index e4d2654e2c..212132ef60 100644 --- a/src/KOKKOS/atom_vec_atomic_kokkos.h +++ b/src/KOKKOS/atom_vec_atomic_kokkos.h @@ -48,7 +48,7 @@ class AtomVecAtomicKokkos : public AtomVecKokkos { void write_data(FILE *, int, double **); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_border_kokkos(int n, DAT::tdual_int_2d k_sendlist, DAT::tdual_xfloat_2d buf,int iswap, int pbc_flag, int *pbc, ExecutionSpace space); diff --git a/src/KOKKOS/atom_vec_bond_kokkos.cpp b/src/KOKKOS/atom_vec_bond_kokkos.cpp index 74c05a506c..60ea024c08 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.cpp +++ b/src/KOKKOS/atom_vec_bond_kokkos.cpp @@ -84,7 +84,7 @@ void AtomVecBondKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_bond_type,atomKK->bond_type,nmax,atomKK->bond_per_atom,"atom:bond_type"); memoryKK->grow_kokkos(atomKK->k_bond_atom,atomKK->bond_atom,nmax,atomKK->bond_per_atom,"atom:bond_atom"); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); if (atom->nextra_grow) @@ -96,7 +96,7 @@ void AtomVecBondKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecBondKokkos::grow_reset() +void AtomVecBondKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_bond_kokkos.h b/src/KOKKOS/atom_vec_bond_kokkos.h index 7ec15450ef..f38ade8f64 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.h +++ b/src/KOKKOS/atom_vec_bond_kokkos.h @@ -52,7 +52,7 @@ class AtomVecBondKokkos : public AtomVecKokkos { int write_data_hybrid(FILE *, double *); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_border_kokkos(int n, DAT::tdual_int_2d k_sendlist, DAT::tdual_xfloat_2d buf,int iswap, int pbc_flag, int *pbc, ExecutionSpace space); diff --git a/src/KOKKOS/atom_vec_charge_kokkos.cpp b/src/KOKKOS/atom_vec_charge_kokkos.cpp index 3f26b1e9ea..f50bc6bd62 100644 --- a/src/KOKKOS/atom_vec_charge_kokkos.cpp +++ b/src/KOKKOS/atom_vec_charge_kokkos.cpp @@ -79,7 +79,7 @@ void AtomVecChargeKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_q,atomKK->q,nmax,"atom:q"); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); if (atom->nextra_grow) @@ -91,7 +91,7 @@ void AtomVecChargeKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecChargeKokkos::grow_reset() +void AtomVecChargeKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_charge_kokkos.h b/src/KOKKOS/atom_vec_charge_kokkos.h index e9ff70bbe1..39d641b844 100644 --- a/src/KOKKOS/atom_vec_charge_kokkos.h +++ b/src/KOKKOS/atom_vec_charge_kokkos.h @@ -53,7 +53,7 @@ class AtomVecChargeKokkos : public AtomVecKokkos { int write_data_hybrid(FILE *, double *); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_border_kokkos(int n, DAT::tdual_int_2d k_sendlist, DAT::tdual_xfloat_2d buf,int iswap, int pbc_flag, int *pbc, ExecutionSpace space); diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.cpp b/src/KOKKOS/atom_vec_dpd_kokkos.cpp index 144ef26f19..2885c292c1 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.cpp +++ b/src/KOKKOS/atom_vec_dpd_kokkos.cpp @@ -93,7 +93,7 @@ void AtomVecDPDKokkos::grow(int n) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); } @@ -101,7 +101,7 @@ void AtomVecDPDKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecDPDKokkos::grow_reset() +void AtomVecDPDKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.h b/src/KOKKOS/atom_vec_dpd_kokkos.h index cec1b82357..e969a28cb8 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.h +++ b/src/KOKKOS/atom_vec_dpd_kokkos.h @@ -61,7 +61,7 @@ class AtomVecDPDKokkos : public AtomVecKokkos { int write_data_hybrid(FILE *, double *); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_comm_kokkos(const int &n, const DAT::tdual_int_2d &k_sendlist, const int & iswap, const DAT::tdual_xfloat_2d &buf, diff --git a/src/KOKKOS/atom_vec_full_kokkos.cpp b/src/KOKKOS/atom_vec_full_kokkos.cpp index 1fdbcbec8c..0f8aaade8a 100644 --- a/src/KOKKOS/atom_vec_full_kokkos.cpp +++ b/src/KOKKOS/atom_vec_full_kokkos.cpp @@ -123,7 +123,7 @@ void AtomVecFullKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_improper_atom4,atomKK->improper_atom4,nmax, atomKK->improper_per_atom,"atom:improper_atom4"); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); if (atom->nextra_grow) @@ -135,7 +135,7 @@ void AtomVecFullKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecFullKokkos::grow_reset() +void AtomVecFullKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_full_kokkos.h b/src/KOKKOS/atom_vec_full_kokkos.h index 33760a8b5f..a2d4fa9cf4 100644 --- a/src/KOKKOS/atom_vec_full_kokkos.h +++ b/src/KOKKOS/atom_vec_full_kokkos.h @@ -52,7 +52,7 @@ class AtomVecFullKokkos : public AtomVecKokkos { int write_data_hybrid(FILE *, double *); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_border_kokkos(int n, DAT::tdual_int_2d k_sendlist, DAT::tdual_xfloat_2d buf,int iswap, int pbc_flag, int *pbc, ExecutionSpace space); diff --git a/src/KOKKOS/atom_vec_hybrid_kokkos.cpp b/src/KOKKOS/atom_vec_hybrid_kokkos.cpp index 40303051b2..8f8a0c8c00 100644 --- a/src/KOKKOS/atom_vec_hybrid_kokkos.cpp +++ b/src/KOKKOS/atom_vec_hybrid_kokkos.cpp @@ -163,7 +163,7 @@ void AtomVecHybridKokkos::grow(int n) // for sub-styles, do this in case // multiple sub-style reallocs of same array occurred - grow_reset(); + grow_pointers(); if (atom->nextra_grow) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) @@ -174,7 +174,7 @@ void AtomVecHybridKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecHybridKokkos::grow_reset() +void AtomVecHybridKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; @@ -216,7 +216,7 @@ void AtomVecHybridKokkos::grow_reset() d_angmom = atomKK->k_angmom.d_view; h_angmom = atomKK->k_angmom.h_view; - for (int k = 0; k < nstyles; k++) styles[k]->grow_reset(); + for (int k = 0; k < nstyles; k++) styles[k]->grow_pointers(); } /* ---------------------------------------------------------------------- diff --git a/src/KOKKOS/atom_vec_hybrid_kokkos.h b/src/KOKKOS/atom_vec_hybrid_kokkos.h index 4cfb186b17..02f9044d73 100644 --- a/src/KOKKOS/atom_vec_hybrid_kokkos.h +++ b/src/KOKKOS/atom_vec_hybrid_kokkos.h @@ -36,7 +36,7 @@ class AtomVecHybridKokkos : public AtomVecKokkos { void process_args(int, char **); void init(); void grow(int); - void grow_reset(); + void grow_pointers(); void copy(int, int, int); void clear_bonus(); void force_clear(int, size_t); diff --git a/src/KOKKOS/atom_vec_molecular_kokkos.cpp b/src/KOKKOS/atom_vec_molecular_kokkos.cpp index f3b4ae98ca..0c4bf483d3 100644 --- a/src/KOKKOS/atom_vec_molecular_kokkos.cpp +++ b/src/KOKKOS/atom_vec_molecular_kokkos.cpp @@ -121,7 +121,7 @@ void AtomVecMolecularKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_improper_atom4,atomKK->improper_atom4,nmax, atomKK->improper_per_atom,"atom:improper_atom4"); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); if (atom->nextra_grow) @@ -133,7 +133,7 @@ void AtomVecMolecularKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecMolecularKokkos::grow_reset() +void AtomVecMolecularKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_molecular_kokkos.h b/src/KOKKOS/atom_vec_molecular_kokkos.h index 06444510e0..cede4f42a8 100644 --- a/src/KOKKOS/atom_vec_molecular_kokkos.h +++ b/src/KOKKOS/atom_vec_molecular_kokkos.h @@ -58,7 +58,7 @@ class AtomVecMolecularKokkos : public AtomVecKokkos { int write_data_hybrid(FILE *, double *); bigint memory_usage(); - void grow_reset(); + void grow_pointers(); int pack_comm_kokkos(const int &n, const DAT::tdual_int_2d &k_sendlist, const int & iswap, const DAT::tdual_xfloat_2d &buf, diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.cpp b/src/KOKKOS/atom_vec_sphere_kokkos.cpp index 67aaa32c21..35f93294a8 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.cpp +++ b/src/KOKKOS/atom_vec_sphere_kokkos.cpp @@ -119,7 +119,7 @@ void AtomVecSphereKokkos::grow(int n) for (int iextra = 0; iextra < atom->nextra_grow; iextra++) modify->fix[atom->extra_grow[iextra]]->grow_arrays(nmax); - grow_reset(); + grow_pointers(); atomKK->sync(Host,ALL_MASK); } @@ -127,7 +127,7 @@ void AtomVecSphereKokkos::grow(int n) reset local array ptrs ------------------------------------------------------------------------- */ -void AtomVecSphereKokkos::grow_reset() +void AtomVecSphereKokkos::grow_pointers() { tag = atomKK->tag; d_tag = atomKK->k_tag.d_view; diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.h b/src/KOKKOS/atom_vec_sphere_kokkos.h index 28c8a3c8f6..3f6d34e8b2 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.h +++ b/src/KOKKOS/atom_vec_sphere_kokkos.h @@ -33,7 +33,7 @@ class AtomVecSphereKokkos : public AtomVecKokkos { ~AtomVecSphereKokkos() {} void init(); void grow(int); - void grow_reset(); + void grow_pointers(); void copy(int, int, int); int pack_comm(int, int *, double *, int, int *); int pack_comm_vel(int, int *, double *, int, int *); -- GitLab From 34778c4919d21fd12d8e9a5ff870c1862bb28157 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 29 Jan 2020 14:10:42 -0700 Subject: [PATCH 019/577] Restore virtual keyword for Kokkos package --- src/atom_vec.h | 66 +++++++++++++++++++++++++------------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/src/atom_vec.h b/src/atom_vec.h index 94517f80ad..b34ee5adb4 100644 --- a/src/atom_vec.h +++ b/src/atom_vec.h @@ -74,41 +74,41 @@ class AtomVec : protected Pointers { virtual void force_clear(int, size_t) {} - void grow(int); + virtual void grow(int); virtual void grow_pointers() {} - void copy(int, int, int); + virtual void copy(int, int, int); virtual void copy_bonus(int, int, int) {} virtual void clear_bonus() {} - int pack_comm(int, int *, double *, int, int *); - int pack_comm_vel(int, int *, double *, int, int *); - void unpack_comm(int, int, double *); - void unpack_comm_vel(int, int, double *); + virtual int pack_comm(int, int *, double *, int, int *); + virtual int pack_comm_vel(int, int *, double *, int, int *); + virtual void unpack_comm(int, int, double *); + virtual void unpack_comm_vel(int, int, double *); virtual int pack_comm_bonus(int, int *, double *) {} virtual void unpack_comm_bonus(int, int, double *) {} - int pack_reverse(int, int, double *); - void unpack_reverse(int, int *, double *); + virtual int pack_reverse(int, int, double *); + virtual void unpack_reverse(int, int *, double *); - int pack_border(int, int *, double *, int, int *); - int pack_border_vel(int, int *, double *, int, int *); - void unpack_border(int, int, double *); - void unpack_border_vel(int, int, double *); + virtual int pack_border(int, int *, double *, int, int *); + virtual int pack_border_vel(int, int *, double *, int, int *); + virtual void unpack_border(int, int, double *); + virtual void unpack_border_vel(int, int, double *); virtual int pack_border_bonus(int, int *, double *) {} virtual int unpack_border_bonus(int, int, double *) {} - int pack_exchange(int, double *); - int unpack_exchange(double *); + virtual int pack_exchange(int, double *); + virtual int unpack_exchange(double *); virtual int pack_exchange_bonus(int, double *) {} virtual int unpack_exchange_bonus(int, double *) {} - int size_restart(); - int pack_restart(int, double *); - int unpack_restart(double *); + virtual int size_restart(); + virtual int pack_restart(int, double *); + virtual int unpack_restart(double *); virtual void pack_restart_pre(int) {} virtual void pack_restart_post(int) {} @@ -118,36 +118,36 @@ class AtomVec : protected Pointers { virtual int pack_restart_bonus(int, double *) {} virtual int unpack_restart_bonus(int, double *) {} - void create_atom(int, double *); + virtual void create_atom(int, double *); virtual void create_atom_post(int) {} - void data_atom(double *, imageint, char **); + virtual void data_atom(double *, imageint, char **); virtual void data_atom_post(int) {} virtual void data_atom_bonus(int, char **) {} virtual void data_body(int, int, int, int *, double *) {} - void pack_data(double **); - void write_data(FILE *, int, double **); + virtual void pack_data(double **); + virtual void write_data(FILE *, int, double **); virtual void pack_data_pre(int) {} virtual void pack_data_post(int) {} - void data_vel(int, char **); - void pack_vel(double **); - void write_vel(FILE *, int, double **); + virtual void data_vel(int, char **); + virtual void pack_vel(double **); + virtual void write_vel(FILE *, int, double **); - int pack_bond(tagint **); - void write_bond(FILE *, int, tagint **, int); - int pack_angle(tagint **); - void write_angle(FILE *, int, tagint **, int); - int pack_dihedral(tagint **); - void write_dihedral(FILE *, int, tagint **, int); - int pack_improper(tagint **); - void write_improper(FILE *, int, tagint **, int); + virtual int pack_bond(tagint **); + virtual void write_bond(FILE *, int, tagint **, int); + virtual int pack_angle(tagint **); + virtual void write_angle(FILE *, int, tagint **, int); + virtual int pack_dihedral(tagint **); + virtual void write_dihedral(FILE *, int, tagint **, int); + virtual int pack_improper(tagint **); + virtual void write_improper(FILE *, int, tagint **, int); virtual int property_atom(char *) {return -1;} virtual void pack_property_atom(int, double *, int, int) {} - bigint memory_usage(); + virtual bigint memory_usage(); virtual bigint memory_usage_bonus() {} protected: -- GitLab From d34f9af2914ff8aa3e214a022509979bb29b638d Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Thu, 30 Jan 2020 14:27:45 -0700 Subject: [PATCH 020/577] fixed bug with writing of data file velocities --- src/atom_vec.cpp | 66 +++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 35 deletions(-) diff --git a/src/atom_vec.cpp b/src/atom_vec.cpp index 77ba68f651..08f9c54e56 100644 --- a/src/atom_vec.cpp +++ b/src/atom_vec.cpp @@ -1979,47 +1979,43 @@ void AtomVec::write_vel(FILE *fp, int n, double **buf) void *pdata; for (i = 0; i < n; i++) { - fprintf(fp,TAGINT_FORMAT " %-1.16e %-1.16e %-1.16e\n", - (tagint) ubuf(buf[i][0]).i,buf[i][1],buf[i][2],buf[i][3]); - - if (ndata_vel) { - j = 4; - for (nn = 0; nn < ndata_vel; nn++) { - pdata = mdata_vel.pdata[nn]; - datatype = mdata_vel.datatype[nn]; - cols = mdata_vel.cols[nn]; - if (datatype == DOUBLE) { - if (cols == 0) { - double *vec = *((double **) pdata); + fprintf(fp,TAGINT_FORMAT,(tagint) ubuf(buf[i][0]).i); + + j = 1; + for (nn = 1; nn < ndata_vel; nn++) { + pdata = mdata_vel.pdata[nn]; + datatype = mdata_vel.datatype[nn]; + cols = mdata_vel.cols[nn]; + if (datatype == DOUBLE) { + if (cols == 0) { + double *vec = *((double **) pdata); + fprintf(fp," %-1.16e",buf[i][j++]); + } else { + double **array = *((double ***) pdata); + for (m = 0; m < cols; m++) fprintf(fp," %-1.16e",buf[i][j++]); - } else { - double **array = *((double ***) pdata); - for (m = 0; m < cols; m++) - fprintf(fp," %-1.16e",buf[i][j++]); - } - } else if (datatype == INT) { - if (cols == 0) { - int *vec = *((int **) pdata); + } + } else if (datatype == INT) { + if (cols == 0) { + int *vec = *((int **) pdata); + fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); + } else { + int **array = *((int ***) pdata); + for (m = 0; m < cols; m++) fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); - } else { - int **array = *((int ***) pdata); - for (m = 0; m < cols; m++) - fprintf(fp," %d",(int) ubuf(buf[i][j++]).i); - } - } else if (datatype == BIGINT) { - if (cols == 0) { - bigint *vec = *((bigint **) pdata); + } + } else if (datatype == BIGINT) { + if (cols == 0) { + bigint *vec = *((bigint **) pdata); + fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); + } else { + bigint **array = *((bigint ***) pdata); + for (m = 0; m < cols; m++) fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); - } else { - bigint **array = *((bigint ***) pdata); - for (m = 0; m < cols; m++) - fprintf(fp," " BIGINT_FORMAT,(bigint) ubuf(buf[i][j++]).i); - } } } } - - fprintf(fp,"\n"); + fprintf(fp,"\n"); } } -- GitLab From 9e8806bd2239d88a83b1c15b1724541b0e8f4d6d Mon Sep 17 00:00:00 2001 From: Vsevak Date: Fri, 31 Jan 2020 21:26:52 +0300 Subject: [PATCH 021/577] Addition to lib/gpu/README for HIP --- lib/gpu/README | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/lib/gpu/README b/lib/gpu/README index 2d98749a40..969417a865 100644 --- a/lib/gpu/README +++ b/lib/gpu/README @@ -67,8 +67,8 @@ library requires installing the CUDA GPU driver and CUDA toolkit for your operating system. Installation of the CUDA SDK is not necessary. In addition to the LAMMPS library, the binary nvc_get_devices will also be built. This can be used to query the names and properties of GPU -devices on your system. A Makefile for OpenCL compilation is provided, -but support for OpenCL use is not currently provided by the developers. +devices on your system. A Makefile for OpenCL and ROCm HIP compilation +is provided, but support for it is not currently provided by the developers. Details of the implementation are provided in: ---- @@ -169,6 +169,25 @@ NOTE: The system-specific setting LAMMPS_SMALLBIG (default), LAMMPS_BIGBIG, src/MAKE/Makefile.foo) should be consistent with that specified when building libgpu.a (i.e. by LMP_INC in the lib/gpu/Makefile.bar). + BUILDING FOR HIP FRAMEWORK + -------------------------------- +1. Install the latest ROCm framework (https://github.com/RadeonOpenCompute/ROCm). +2. GPU sorting requires installing hipcub +(https://github.com/ROCmSoftwarePlatform/hipCUB). The HIP CUDA-backend +additionally requires cub (https://nvlabs.github.io/cub). Download and +extract the cub directory to lammps/lib/gpu/ or specify an appropriate +path in lammps/lib/gpu/Makefile.hip. +3. In Makefile.hip it is possible to specify the target platform via +export HIP_PLATFORM=hcc or HIP_PLATFORM=nvcc as well as the target +architecture (gfx803, gfx900, gfx906 etc.) +4. If your MPI implementation does not support `mpicxx --showme` command, +it is required to specify the corresponding MPI compiler and linker flags +in lammps/lib/gpu/Makefile.hip and in lammps/src/MAKE/OPTIONS/Makefile.hip. +5. Building the GPU library (libgpu.a): + cd lammps/lib/gpu; make -f Makefile.hip -j +6. Building the LAMMPS executable (lmp_hip): + cd ../../src; make hip -j + EXAMPLE CONVENTIONAL BUILD PROCESS -------------------------------- -- GitLab From 33fc22b752c3652df832662a91a1e5fc887c9200 Mon Sep 17 00:00:00 2001 From: Vsevak Date: Mon, 3 Feb 2020 01:55:20 +0300 Subject: [PATCH 022/577] Fix echo in Makefile --- lib/gpu/Makefile.hip | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/gpu/Makefile.hip b/lib/gpu/Makefile.hip index 5c9f251004..1c8e0683ca 100644 --- a/lib/gpu/Makefile.hip +++ b/lib/gpu/Makefile.hip @@ -137,7 +137,7 @@ $(OBJ_DIR)/lal_%.o: lal_%.cpp $(CUHS) $(ALL_H) $(LIB_DIR)/libgpu.a: $(OBJS) $(AR) -crs $@ $(OBJS) - echo "export HIP_PLATFORM := $(HIP_PLATFORM)\n$(HIP_LIBS_TARGET)" > 'Makefile.lammps' + echo -e "export HIP_PLATFORM := $(HIP_PLATFORM)\n$(HIP_LIBS_TARGET)" > 'Makefile.lammps' # test app building -- GitLab From 5f68f3006f1eafaffdb13b3e85220b5d8ac0dd2a Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 8 Feb 2020 15:12:26 -0500 Subject: [PATCH 023/577] replace Fix::box_change_xxx variables with Fix::box_change bitmask and add check to Domain::init() This allows a more specific tracking of whether multiple fixes are modifying the same box parameter and error out in that case. --- src/RIGID/fix_rigid_nh.cpp | 4 ++++ src/RIGID/fix_rigid_nh_small.cpp | 4 ++++ src/RIGID/fix_rigid_nph.cpp | 1 - src/RIGID/fix_rigid_nph_small.cpp | 1 - src/RIGID/fix_rigid_npt.cpp | 1 - src/RIGID/fix_rigid_npt_small.cpp | 1 - src/SHOCK/fix_msst.cpp | 15 +++++++++----- src/SRD/fix_srd.cpp | 11 ++++++---- src/USER-BOCS/fix_bocs.cpp | 8 ++++++-- src/USER-MISC/fix_npt_cauchy.cpp | 8 ++++++-- src/USER-OMP/fix_rigid_nph_omp.cpp | 1 - src/USER-OMP/fix_rigid_npt_omp.cpp | 1 - src/USER-QTB/fix_qbmsst.cpp | 12 ++++++----- src/USER-UEF/fix_nh_uef.cpp | 2 +- src/domain.cpp | 33 +++++++++++++++++++++++++++--- src/fix.cpp | 2 +- src/fix.h | 11 +++++++--- src/fix_balance.cpp | 2 +- src/fix_box_relax.cpp | 9 ++++++-- src/fix_deform.cpp | 8 ++++++-- src/fix_nh.cpp | 8 ++++++-- src/fix_press_berendsen.cpp | 6 ++++-- 22 files changed, 108 insertions(+), 41 deletions(-) diff --git a/src/RIGID/fix_rigid_nh.cpp b/src/RIGID/fix_rigid_nh.cpp index 6ffb997ffa..1df7f34532 100644 --- a/src/RIGID/fix_rigid_nh.cpp +++ b/src/RIGID/fix_rigid_nh.cpp @@ -106,6 +106,10 @@ FixRigidNH::FixRigidNH(LAMMPS *lmp, int narg, char **arg) : p_period[0] != p_period[2])) error->all(FLERR,"Invalid fix rigid npt/nph command pressure settings"); + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + if ((tstat_flag && t_period <= 0.0) || (p_flag[0] && p_period[0] <= 0.0) || (p_flag[1] && p_period[1] <= 0.0) || diff --git a/src/RIGID/fix_rigid_nh_small.cpp b/src/RIGID/fix_rigid_nh_small.cpp index 136796ce18..5b75640549 100644 --- a/src/RIGID/fix_rigid_nh_small.cpp +++ b/src/RIGID/fix_rigid_nh_small.cpp @@ -120,6 +120,10 @@ FixRigidNHSmall::FixRigidNHSmall(LAMMPS *lmp, int narg, char **arg) : p_period[0] != p_period[2])) error->all(FLERR,"Invalid fix rigid/small npt/nph command pressure settings"); + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + if ((tstat_flag && t_period <= 0.0) || (p_flag[0] && p_period[0] <= 0.0) || (p_flag[1] && p_period[1] <= 0.0) || diff --git a/src/RIGID/fix_rigid_nph.cpp b/src/RIGID/fix_rigid_nph.cpp index 706e08ec12..5c3b5390aa 100644 --- a/src/RIGID/fix_rigid_nph.cpp +++ b/src/RIGID/fix_rigid_nph.cpp @@ -33,7 +33,6 @@ FixRigidNPH::FixRigidNPH(LAMMPS *lmp, int narg, char **arg) : scalar_flag = 1; restart_global = 1; - box_change_size = 1; extscalar = 1; // error checks diff --git a/src/RIGID/fix_rigid_nph_small.cpp b/src/RIGID/fix_rigid_nph_small.cpp index 32ac58220d..7769ced807 100644 --- a/src/RIGID/fix_rigid_nph_small.cpp +++ b/src/RIGID/fix_rigid_nph_small.cpp @@ -33,7 +33,6 @@ FixRigidNPHSmall::FixRigidNPHSmall(LAMMPS *lmp, int narg, char **arg) : scalar_flag = 1; restart_global = 1; - box_change_size = 1; extscalar = 1; // error checks diff --git a/src/RIGID/fix_rigid_npt.cpp b/src/RIGID/fix_rigid_npt.cpp index 1f19fb4ec7..5f3fde669c 100644 --- a/src/RIGID/fix_rigid_npt.cpp +++ b/src/RIGID/fix_rigid_npt.cpp @@ -33,7 +33,6 @@ FixRigidNPT::FixRigidNPT(LAMMPS *lmp, int narg, char **arg) : scalar_flag = 1; restart_global = 1; - box_change_size = 1; extscalar = 1; // error checks diff --git a/src/RIGID/fix_rigid_npt_small.cpp b/src/RIGID/fix_rigid_npt_small.cpp index e8924be79f..d3bd5b8f57 100644 --- a/src/RIGID/fix_rigid_npt_small.cpp +++ b/src/RIGID/fix_rigid_npt_small.cpp @@ -33,7 +33,6 @@ FixRigidNPTSmall::FixRigidNPTSmall(LAMMPS *lmp, int narg, char **arg) : scalar_flag = 1; restart_global = 1; - box_change_size = 1; extscalar = 1; // error checks diff --git a/src/SHOCK/fix_msst.cpp b/src/SHOCK/fix_msst.cpp index 2e9f751824..67b2a7fb0f 100644 --- a/src/SHOCK/fix_msst.cpp +++ b/src/SHOCK/fix_msst.cpp @@ -46,7 +46,6 @@ FixMSST::FixMSST(LAMMPS *lmp, int narg, char **arg) : if (narg < 4) error->all(FLERR,"Illegal fix msst command"); restart_global = 1; - box_change_size = 1; time_integrate = 1; scalar_flag = 1; vector_flag = 1; @@ -78,10 +77,16 @@ FixMSST::FixMSST(LAMMPS *lmp, int narg, char **arg) : dftb = 0; beta = 0.0; - if (strcmp(arg[3],"x") == 0) direction = 0; - else if (strcmp(arg[3],"y") == 0) direction = 1; - else if (strcmp(arg[3],"z") == 0) direction = 2; - else error->all(FLERR,"Illegal fix msst command"); + if (strcmp(arg[3],"x") == 0) { + direction = 0; + box_change |= BOX_CHANGE_X; + } else if (strcmp(arg[3],"y") == 0) { + direction = 1; + box_change |= BOX_CHANGE_Y; + } else if (strcmp(arg[3],"z") == 0) { + direction = 2; + box_change |= BOX_CHANGE_Z; + } else error->all(FLERR,"Illegal fix msst command"); velocity = force->numeric(FLERR,arg[4]); if (velocity < 0) error->all(FLERR,"Illegal fix msst command"); diff --git a/src/SRD/fix_srd.cpp b/src/SRD/fix_srd.cpp index d5eec91f50..d87851381f 100644 --- a/src/SRD/fix_srd.cpp +++ b/src/SRD/fix_srd.cpp @@ -375,13 +375,16 @@ void FixSRD::init() change_size = change_shape = deformflag = 0; if (domain->nonperiodic == 2) change_size = 1; + + Fix **fixes = modify->fix; for (int i = 0; i < modify->nfix; i++) { - if (modify->fix[i]->box_change_size) change_size = 1; - if (modify->fix[i]->box_change_shape) change_shape = 1; - if (strcmp(modify->fix[i]->style,"deform") == 0) { + if (fixes[i]->box_change & BOX_CHANGE_SIZE) change_size = 1; + if (fixes[i]->box_change & BOX_CHANGE_SHAPE) change_shape = 1; + if (strcmp(fixes[i]->style,"deform") == 0) { deformflag = 1; FixDeform *deform = (FixDeform *) modify->fix[i]; - if (deform->box_change_shape && deform->remapflag != Domain::V_REMAP) + if ((deform->box_change & BOX_CHANGE_SHAPE) + && deform->remapflag != Domain::V_REMAP) error->all(FLERR,"Using fix srd with inconsistent " "fix deform remap option"); } diff --git a/src/USER-BOCS/fix_bocs.cpp b/src/USER-BOCS/fix_bocs.cpp index adce231bf1..3543c2f156 100644 --- a/src/USER-BOCS/fix_bocs.cpp +++ b/src/USER-BOCS/fix_bocs.cpp @@ -292,8 +292,12 @@ FixBocs::FixBocs(LAMMPS *lmp, int narg, char **arg) : if (p_flag[i]) pstat_flag = 1; if (pstat_flag) { - if (p_flag[0] || p_flag[1] || p_flag[2]) box_change_size = 1; - if (p_flag[3] || p_flag[4] || p_flag[5]) box_change_shape = 1; + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + if (p_flag[3]) box_change |= BOX_CHANGE_YZ; + if (p_flag[4]) box_change |= BOX_CHANGE_XZ; + if (p_flag[5]) box_change |= BOX_CHANGE_XY; no_change_box = 1; if (allremap == 0) restart_pbc = 1; diff --git a/src/USER-MISC/fix_npt_cauchy.cpp b/src/USER-MISC/fix_npt_cauchy.cpp index 1b0deb5ae3..7a4a34bd00 100644 --- a/src/USER-MISC/fix_npt_cauchy.cpp +++ b/src/USER-MISC/fix_npt_cauchy.cpp @@ -492,8 +492,12 @@ FixNPTCauchy::FixNPTCauchy(LAMMPS *lmp, int narg, char **arg) : if (p_flag[i]) pstat_flag = 1; if (pstat_flag) { - if (p_flag[0] || p_flag[1] || p_flag[2]) box_change_size = 1; - if (p_flag[3] || p_flag[4] || p_flag[5]) box_change_shape = 1; + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + if (p_flag[3]) box_change |= BOX_CHANGE_YZ; + if (p_flag[4]) box_change |= BOX_CHANGE_XZ; + if (p_flag[5]) box_change |= BOX_CHANGE_XY; no_change_box = 1; if (allremap == 0) restart_pbc = 1; diff --git a/src/USER-OMP/fix_rigid_nph_omp.cpp b/src/USER-OMP/fix_rigid_nph_omp.cpp index 31d53868c8..ff192341e4 100644 --- a/src/USER-OMP/fix_rigid_nph_omp.cpp +++ b/src/USER-OMP/fix_rigid_nph_omp.cpp @@ -33,7 +33,6 @@ FixRigidNPHOMP::FixRigidNPHOMP(LAMMPS *lmp, int narg, char **arg) : scalar_flag = 1; restart_global = 1; - box_change_size = 1; extscalar = 1; // error checks diff --git a/src/USER-OMP/fix_rigid_npt_omp.cpp b/src/USER-OMP/fix_rigid_npt_omp.cpp index 1e7c139d52..6da51e6220 100644 --- a/src/USER-OMP/fix_rigid_npt_omp.cpp +++ b/src/USER-OMP/fix_rigid_npt_omp.cpp @@ -33,7 +33,6 @@ FixRigidNPTOMP::FixRigidNPTOMP(LAMMPS *lmp, int narg, char **arg) : scalar_flag = 1; restart_global = 1; - box_change_size = 1; extscalar = 1; // error checks diff --git a/src/USER-QTB/fix_qbmsst.cpp b/src/USER-QTB/fix_qbmsst.cpp index abbf1701b8..27b1dcd4df 100644 --- a/src/USER-QTB/fix_qbmsst.cpp +++ b/src/USER-QTB/fix_qbmsst.cpp @@ -45,13 +45,16 @@ FixQBMSST::FixQBMSST(LAMMPS *lmp, int narg, char **arg) : { if (narg < 5) error->all(FLERR,"Illegal fix qbmsst command"); - if ( strcmp(arg[3],"x") == 0 ) + if ( strcmp(arg[3],"x") == 0 ) { direction = 0; - else if ( strcmp(arg[3],"y") == 0 ) + box_change |= BOX_CHANGE_X; + } else if ( strcmp(arg[3],"y") == 0 ) { direction = 1; - else if ( strcmp(arg[3],"z") == 0 ) + box_change |= BOX_CHANGE_Y; + } else if ( strcmp(arg[3],"z") == 0 ) { direction = 2; - else { + box_change |= BOX_CHANGE_Z; + } else { error->all(FLERR,"Illegal fix qbmsst command"); } velocity = atof(arg[4]); @@ -64,7 +67,6 @@ FixQBMSST::FixQBMSST(LAMMPS *lmp, int narg, char **arg) : extvector = 0; nevery = 1; restart_global = 1; - box_change_size = 1; time_integrate = 1; scalar_flag = 1; vector_flag = 1; diff --git a/src/USER-UEF/fix_nh_uef.cpp b/src/USER-UEF/fix_nh_uef.cpp index 8873688eb7..5c98a2dc85 100644 --- a/src/USER-UEF/fix_nh_uef.cpp +++ b/src/USER-UEF/fix_nh_uef.cpp @@ -163,7 +163,7 @@ FixNHUef::FixNHUef(LAMMPS *lmp, int narg, char **arg) : // flag that I change the box here (in case of nvt) - box_change_shape = 1; + box_change |= BOX_CHANGE_SHAPE; // initialize the UEFBox class which computes the box at each step diff --git a/src/domain.cpp b/src/domain.cpp index e894682556..efa2ef00cf 100644 --- a/src/domain.cpp +++ b/src/domain.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include "style_region.h" #include "atom.h" #include "atom_vec.h" @@ -133,13 +134,39 @@ void Domain::init() box_change_size = box_change_shape = box_change_domain = 0; + // flags for detecting, if multiple fixes try to change the + // same box size or shape parameter + + int box_change_x=0, box_change_y=0, box_change_z=0; + int box_change_yz=0, box_change_xz=0, box_change_xy=0; + Fix **fixes = modify->fix; + if (nonperiodic == 2) box_change_size = 1; for (int i = 0; i < modify->nfix; i++) { - if (modify->fix[i]->box_change_size) box_change_size = 1; - if (modify->fix[i]->box_change_shape) box_change_shape = 1; - if (modify->fix[i]->box_change_domain) box_change_domain = 1; + if (fixes[i]->box_change & Fix::BOX_CHANGE_SIZE) box_change_size = 1; + if (fixes[i]->box_change & Fix::BOX_CHANGE_SHAPE) box_change_shape = 1; + if (fixes[i]->box_change & Fix::BOX_CHANGE_DOMAIN) box_change_domain = 1; + if (fixes[i]->box_change & Fix::BOX_CHANGE_X) box_change_x++; + if (fixes[i]->box_change & Fix::BOX_CHANGE_Y) box_change_y++; + if (fixes[i]->box_change & Fix::BOX_CHANGE_Z) box_change_z++; + if (fixes[i]->box_change & Fix::BOX_CHANGE_YZ) box_change_yz++; + if (fixes[i]->box_change & Fix::BOX_CHANGE_XZ) box_change_xz++; + if (fixes[i]->box_change & Fix::BOX_CHANGE_XY) box_change_xy++; } + std::string mesg = "Must not have multiple fixes change box parameter "; + +#define CHECK_BOX_FIX_ERROR(par) \ + if (box_change_ ## par > 1) error->all(FLERR,(mesg + #par).c_str()) + + CHECK_BOX_FIX_ERROR(x); + CHECK_BOX_FIX_ERROR(y); + CHECK_BOX_FIX_ERROR(z); + CHECK_BOX_FIX_ERROR(yz); + CHECK_BOX_FIX_ERROR(xz); + CHECK_BOX_FIX_ERROR(xy); +#undef CHECK_BOX_FIX_ERROR + box_change = 0; if (box_change_size || box_change_shape || box_change_domain) box_change = 1; diff --git a/src/fix.cpp b/src/fix.cpp index d86acf0ae4..9c883a6897 100644 --- a/src/fix.cpp +++ b/src/fix.cpp @@ -58,7 +58,7 @@ Fix::Fix(LAMMPS *lmp, int /*narg*/, char **arg) : restart_global = restart_peratom = restart_file = 0; force_reneighbor = 0; - box_change_size = box_change_shape = box_change_domain = 0; + box_change = NO_BOX_CHANGE; thermo_energy = 0; thermo_virial = 0; rigid_flag = 0; diff --git a/src/fix.h b/src/fix.h index bcab6f289e..921778ae98 100644 --- a/src/fix.h +++ b/src/fix.h @@ -30,9 +30,14 @@ class Fix : protected Pointers { int restart_file; // 1 if Fix writes own restart file, 0 if not int force_reneighbor; // 1 if Fix forces reneighboring, 0 if not - int box_change_size; // 1 if Fix changes box size, 0 if not - int box_change_shape; // 1 if Fix changes box shape, 0 if not - int box_change_domain; // 1 if Fix changes proc sub-domains, 0 if not + int box_change; // >0 if Fix changes box size, shape, or sub-domains, 0 if not + enum { + NO_BOX_CHANGE = 0, BOX_CHANGE_ANY = 1<<0, BOX_CHANGE_DOMAIN = 1<<1, + BOX_CHANGE_X = 1<<2, BOX_CHANGE_Y = 1<<3, BOX_CHANGE_Z = 1<<4, + BOX_CHANGE_YZ = 1<<5, BOX_CHANGE_XZ = 1<<6, BOX_CHANGE_XY = 1<<7, + BOX_CHANGE_SIZE = BOX_CHANGE_X | BOX_CHANGE_Y | BOX_CHANGE_Z, + BOX_CHANGE_SHAPE = BOX_CHANGE_YZ | BOX_CHANGE_XZ | BOX_CHANGE_XY + }; bigint next_reneighbor; // next timestep to force a reneighboring int thermo_energy; // 1 if fix_modify enabled ThEng, 0 if not diff --git a/src/fix_balance.cpp b/src/fix_balance.cpp index 5ca1ec124a..b178cca83b 100644 --- a/src/fix_balance.cpp +++ b/src/fix_balance.cpp @@ -39,7 +39,7 @@ FixBalance::FixBalance(LAMMPS *lmp, int narg, char **arg) : { if (narg < 6) error->all(FLERR,"Illegal fix balance command"); - box_change_domain = 1; + box_change = BOX_CHANGE_DOMAIN; scalar_flag = 1; extscalar = 0; vector_flag = 1; diff --git a/src/fix_box_relax.cpp b/src/fix_box_relax.cpp index c19ea918b4..8d6111c0a0 100644 --- a/src/fix_box_relax.cpp +++ b/src/fix_box_relax.cpp @@ -218,8 +218,13 @@ FixBoxRelax::FixBoxRelax(LAMMPS *lmp, int narg, char **arg) : } else error->all(FLERR,"Illegal fix box/relax command"); } - if (p_flag[0] || p_flag[1] || p_flag[2]) box_change_size = 1; - if (p_flag[3] || p_flag[4] || p_flag[5]) box_change_shape = 1; + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + if (p_flag[3]) box_change |= BOX_CHANGE_YZ; + if (p_flag[4]) box_change |= BOX_CHANGE_XZ; + if (p_flag[5]) box_change |= BOX_CHANGE_XY; + if (allremap == 0) restart_pbc = 1; // error checks diff --git a/src/fix_deform.cpp b/src/fix_deform.cpp index 9d84c4bb62..4ecfa6f433 100644 --- a/src/fix_deform.cpp +++ b/src/fix_deform.cpp @@ -211,8 +211,12 @@ rfix(NULL), irregular(NULL), set(NULL) if (set[i].style == NONE) dimflag[i] = 0; else dimflag[i] = 1; - if (dimflag[0] || dimflag[1] || dimflag[2]) box_change_size = 1; - if (dimflag[3] || dimflag[4] || dimflag[5]) box_change_shape = 1; + if (dimflag[0]) box_change |= BOX_CHANGE_X; + if (dimflag[1]) box_change |= BOX_CHANGE_Y; + if (dimflag[2]) box_change |= BOX_CHANGE_Z; + if (dimflag[3]) box_change |= BOX_CHANGE_YZ; + if (dimflag[4]) box_change |= BOX_CHANGE_XZ; + if (dimflag[5]) box_change |= BOX_CHANGE_XY; // no tensile deformation on shrink-wrapped dims // b/c shrink wrap will change box-length diff --git a/src/fix_nh.cpp b/src/fix_nh.cpp index bb3fe7559c..e397e3367a 100644 --- a/src/fix_nh.cpp +++ b/src/fix_nh.cpp @@ -476,8 +476,12 @@ FixNH::FixNH(LAMMPS *lmp, int narg, char **arg) : if (p_flag[i]) pstat_flag = 1; if (pstat_flag) { - if (p_flag[0] || p_flag[1] || p_flag[2]) box_change_size = 1; - if (p_flag[3] || p_flag[4] || p_flag[5]) box_change_shape = 1; + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + if (p_flag[3]) box_change |= BOX_CHANGE_YZ; + if (p_flag[4]) box_change |= BOX_CHANGE_XZ; + if (p_flag[5]) box_change |= BOX_CHANGE_XY; no_change_box = 1; if (allremap == 0) restart_pbc = 1; diff --git a/src/fix_press_berendsen.cpp b/src/fix_press_berendsen.cpp index c090c554e2..184f02c440 100644 --- a/src/fix_press_berendsen.cpp +++ b/src/fix_press_berendsen.cpp @@ -40,8 +40,6 @@ FixPressBerendsen::FixPressBerendsen(LAMMPS *lmp, int narg, char **arg) : { if (narg < 5) error->all(FLERR,"Illegal fix press/berendsen command"); - box_change_size = 1; - // Berendsen barostat applied every step nevery = 1; @@ -204,6 +202,10 @@ FixPressBerendsen::FixPressBerendsen(LAMMPS *lmp, int narg, char **arg) : (p_flag[2] && p_period[2] <= 0.0)) error->all(FLERR,"Fix press/berendsen damping parameters must be > 0.0"); + if (p_flag[0]) box_change |= BOX_CHANGE_X; + if (p_flag[1]) box_change |= BOX_CHANGE_Y; + if (p_flag[2]) box_change |= BOX_CHANGE_Z; + // pstyle = ISO if XYZ coupling or XY coupling in 2d -> 1 dof // else pstyle = ANISO -> 3 dof -- GitLab From 8f3c94f33b3eb1fc2a6b4e722a3c30eece4fa831 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 8 Feb 2020 15:22:54 -0500 Subject: [PATCH 024/577] document new error message --- doc/src/Errors_messages.rst | 3 +++ src/domain.h | 4 ++++ 2 files changed, 7 insertions(+) diff --git a/doc/src/Errors_messages.rst b/doc/src/Errors_messages.rst index bbe84de065..f89b5f5b88 100644 --- a/doc/src/Errors_messages.rst +++ b/doc/src/Errors_messages.rst @@ -5815,6 +5815,9 @@ Doc page with :doc:`WARNING messages ` Cannot use the temper command with only one processor partition. Use the -partition command-line option. +*Must not have multiple fixes change box parameter ...* + Self-explanatory. + *Must read Atoms before Angles* The Atoms section of a data file must come before an Angles section. diff --git a/src/domain.h b/src/domain.h index a0bda8ae72..0ce31a8b4a 100644 --- a/src/domain.h +++ b/src/domain.h @@ -282,6 +282,10 @@ E: Both sides of boundary must be periodic Cannot specify a boundary as periodic only on the lo or hi side. Must be periodic on both sides. +E: Must not have multiple fixes change box parameter ... + +Self-explanatory. + U: Box bounds are invalid The box boundaries specified in the read_data file are invalid. The -- GitLab From f82892c45a5ca45fa01856f4e031e3e9cec855da Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 8 Feb 2020 15:28:10 -0500 Subject: [PATCH 025/577] refactor one more fix --- src/SHOCK/fix_append_atoms.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/SHOCK/fix_append_atoms.cpp b/src/SHOCK/fix_append_atoms.cpp index 5e85b39076..1a6b128cd5 100644 --- a/src/SHOCK/fix_append_atoms.cpp +++ b/src/SHOCK/fix_append_atoms.cpp @@ -40,7 +40,6 @@ FixAppendAtoms::FixAppendAtoms(LAMMPS *lmp, int narg, char **arg) : { force_reneighbor = 1; next_reneighbor = -1; - box_change_size = 1; time_depend = 1; if (narg < 4) error->all(FLERR,"Illegal fix append/atoms command"); @@ -75,35 +74,41 @@ FixAppendAtoms::FixAppendAtoms(LAMMPS *lmp, int narg, char **arg) : if (strcmp(arg[iarg],"xlo") == 0) { error->all(FLERR,"Only zhi currently implemented for fix append/atoms"); xloflag = 1; + box_change |= BOX_CHANGE_X; iarg++; if (domain->boundary[0][0] != 3) error->all(FLERR,"Append boundary must be shrink/minimum"); } else if (strcmp(arg[iarg],"xhi") == 0) { error->all(FLERR,"Only zhi currently implemented for fix append/atoms"); xhiflag = 1; + box_change |= BOX_CHANGE_X; iarg++; if (domain->boundary[0][1] != 3) error->all(FLERR,"Append boundary must be shrink/minimum"); } else if (strcmp(arg[iarg],"ylo") == 0) { error->all(FLERR,"Only zhi currently implemented for fix append/atoms"); yloflag = 1; + box_change |= BOX_CHANGE_Y; iarg++; if (domain->boundary[1][0] != 3) error->all(FLERR,"Append boundary must be shrink/minimum"); } else if (strcmp(arg[iarg],"yhi") == 0) { error->all(FLERR,"Only zhi currently implemented for fix append/atoms"); yhiflag = 1; + box_change |= BOX_CHANGE_Y; iarg++; if (domain->boundary[1][1] != 3) error->all(FLERR,"Append boundary must be shrink/minimum"); } else if (strcmp(arg[iarg],"zlo") == 0) { error->all(FLERR,"Only zhi currently implemented for fix append/atoms"); zloflag = 1; + box_change |= BOX_CHANGE_Z; iarg++; if (domain->boundary[2][0] != 3) error->all(FLERR,"Append boundary must be shrink/minimum"); } else if (strcmp(arg[iarg],"zhi") == 0) { zhiflag = 1; + box_change |= BOX_CHANGE_Z; iarg++; if (domain->boundary[2][1] != 3) error->all(FLERR,"Append boundary must be shrink/minimum"); -- GitLab From 1430d1cb126fa7df1bf35527a82760923e1cbb93 Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Sat, 8 Feb 2020 15:30:13 -0500 Subject: [PATCH 026/577] ...and one more --- src/USER-UEF/fix_nh_uef.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/USER-UEF/fix_nh_uef.cpp b/src/USER-UEF/fix_nh_uef.cpp index 5c98a2dc85..01e2081aca 100644 --- a/src/USER-UEF/fix_nh_uef.cpp +++ b/src/USER-UEF/fix_nh_uef.cpp @@ -244,7 +244,7 @@ void FixNHUef::init() for (int i=0; i < modify->nfix; i++) { if (strcmp(modify->fix[i]->id,id) != 0) - if (modify->fix[i]->box_change_shape != 0) + if ((modify->fix[i]->box_change & BOX_CHANGE_SHAPE) != 0) error->all(FLERR,"Can't use another fix which changes box shape with fix/nvt/npt/uef"); } -- GitLab From 994e1318dd1866201546e98f76064853edeb5731 Mon Sep 17 00:00:00 2001 From: julient31 Date: Mon, 17 Feb 2020 16:59:01 -0700 Subject: [PATCH 027/577] Commit JT 021720 - initial commit - added corrected Neel, new E and w calc. --- src/SPIN/pair_spin_neel.cpp | 127 +++++++++++++++++++++++++----------- src/SPIN/pair_spin_neel.h | 1 + 2 files changed, 89 insertions(+), 39 deletions(-) diff --git a/src/SPIN/pair_spin_neel.cpp b/src/SPIN/pair_spin_neel.cpp index 4a5d453de2..811276cac5 100644 --- a/src/SPIN/pair_spin_neel.cpp +++ b/src/SPIN/pair_spin_neel.cpp @@ -259,7 +259,8 @@ void PairSpinNeel::compute(int eflag, int vflag) } if (eflag) { - evdwl = (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); + // evdwl = (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); + evdwl = compute_neel_energy(i,j,rsq,eij,spi,spj); evdwl *= 0.5*hbar; } else evdwl = 0.0; @@ -365,65 +366,69 @@ void PairSpinNeel::compute_single_pair(int ii, double fmi[3]) /* ---------------------------------------------------------------------- */ -void PairSpinNeel::compute_neel(int i, int j, double rsq, double eij[3], double fmi[3], double spi[3], double spj[3]) +void PairSpinNeel::compute_neel(int i, int j, double rsq, double eij[3], double fmi[3], double spi[3], double spj[3]) { int *type = atom->type; int itype, jtype; itype = type[i]; jtype = type[j]; - double gij, q1ij, q2ij, ra; + double qr,gr,g1r,q1r,q2r,ra; double pdx, pdy, pdz; double pq1x, pq1y, pq1z; double pq2x, pq2y, pq2z; + double eij_si,eij_sj,si_sj,eij_si_2,eij_sj_3,coeff1; - // pseudo-dipolar component + // compute Neel's functions ra = rsq/g3[itype][jtype]/g3[itype][jtype]; - gij = 4.0*g1[itype][jtype]*ra; - gij *= (1.0-g2[itype][jtype]*ra); - gij *= exp(-ra); + gr = 4.0*g1[itype][jtype]*ra; + gr *= (1.0-g2[itype][jtype]*ra); + gr *= exp(-ra); - double scalar_eij_si = eij[0]*spi[0] + eij[1]*spi[1] + eij[2]*spi[2]; - double scalar_eij_sj = eij[0]*spj[0] + eij[1]*spj[1] + eij[2]*spj[2]; - double scalar_si_sj = spi[0]*spj[0] + spi[1]*spj[1] + spi[2]*spj[2]; + ra = rsq/q3[itype][jtype]/q3[itype][jtype]; + qr = 4.0*q1[itype][jtype]*ra; + qr *= (1.0-q2[itype][jtype]*ra); + qr *= exp(-ra); - double gij_eij_sj = gij*scalar_eij_sj; - double gij_3 = gij/3.0; - pdx = gij_eij_sj*eij[0] - gij_3*spj[0]; - pdy = gij_eij_sj*eij[1] - gij_3*spj[1]; - pdz = gij_eij_sj*eij[2] - gij_3*spj[2]; + g1r = (gr + 12.0*qr/35.0); + q1r = 9.0*qr/5.0; + q2r = -2.0*qr/5.0; - // pseudo-quadrupolar component + // pseudo-dipolar component + + eij_si = eij[0]*spi[0] + eij[1]*spi[1] + eij[2]*spi[2]; + eij_sj = eij[0]*spj[0] + eij[1]*spj[1] + eij[2]*spj[2]; + si_sj = spi[0]*spj[0] + spi[1]*spj[1] + spi[2]*spj[2]; - ra = rsq/q3[itype][jtype]/q3[itype][jtype]; - q1ij = 4.0*q1[itype][jtype]*ra; - q1ij *= (1.0-q2[itype][jtype]*ra); - q1ij *= exp(-ra); - q2ij = (-2.0*q1ij/9.0); + pdx = g1r*(eij_sj*eij[0] - spj[0]/3.0); + pdy = g1r*(eij_sj*eij[1] - spj[1]/3.0); + pdz = g1r*(eij_sj*eij[2] - spj[2]/3.0); - double scalar_eij_si_2 = scalar_eij_si*scalar_eij_si; - pq1x = -(scalar_eij_si_2*scalar_eij_si_2 - scalar_si_sj/3.0)*spj[0]/3.0; - pq1y = -(scalar_eij_si_2*scalar_eij_si_2 - scalar_si_sj/3.0)*spj[1]/3.0; - pq1z = -(scalar_eij_si_2*scalar_eij_si_2 - scalar_si_sj/3.0)*spj[2]/3.0; + // pseudo-quadrupolar components - double pqt1 = (scalar_eij_sj*scalar_eij_sj-scalar_si_sj/3.0); - pq1x += pqt1*(2.0*scalar_eij_si*eij[0] - spj[0]/3.0); - pq1y += pqt1*(2.0*scalar_eij_si*eij[1] - spj[1]/3.0); - pq1z += pqt1*(2.0*scalar_eij_si*eij[2] - spj[2]/3.0); + eij_si_2 = eij_si*eij_si; + pq1x = -(eij_si_2 - si_sj/3.0)*spj[0]/3.0; + pq1y = -(eij_si_2 - si_sj/3.0)*spj[1]/3.0; + pq1z = -(eij_si_2 - si_sj/3.0)*spj[2]/3.0; - pq1x *= q1ij; - pq1y *= q1ij; - pq1z *= q1ij; + coeff1 = (eij_sj*eij_sj-si_sj/3.0); + pq1x += coeff1*(2.0*eij_si*eij[0] - spj[0]/3.0); + pq1y += coeff1*(2.0*eij_si*eij[1] - spj[1]/3.0); + pq1z += coeff1*(2.0*eij_si*eij[2] - spj[2]/3.0); - double scalar_eij_sj_3 = scalar_eij_sj*scalar_eij_sj*scalar_eij_sj; - pq2x = 3.0*scalar_eij_si_2*scalar_eij_sj*eij[0] + scalar_eij_sj_3*eij[0]; - pq2y = 3.0*scalar_eij_si_2*scalar_eij_sj*eij[1] + scalar_eij_sj_3*eij[1]; - pq2z = 3.0*scalar_eij_si_2*scalar_eij_sj*eij[2] + scalar_eij_sj_3*eij[2]; + pq1x *= q1r; + pq1y *= q1r; + pq1z *= q1r; - pq2x *= q2ij; - pq2y *= q2ij; - pq2z *= q2ij; + eij_sj_3 = eij_sj*eij_sj*eij_sj; + pq2x = 3.0*eij_si_2*eij_sj*eij[0] + eij_sj_3*eij[0]; + pq2y = 3.0*eij_si_2*eij_sj*eij[1] + eij_sj_3*eij[1]; + pq2z = 3.0*eij_si_2*eij_sj*eij[2] + eij_sj_3*eij[2]; + + pq2x *= q2r; + pq2y *= q2r; + pq2z *= q2r; // adding three contributions @@ -563,6 +568,50 @@ void PairSpinNeel::compute_neel_mech(int i, int j, double rsq, double eij[3], do fi[2] = pdz + pq1z + pq2z; } +/* ---------------------------------------------------------------------- */ + +double PairSpinNeel::compute_neel_energy(int i, int j, double rsq, double eij[3], double spi[3], double spj[3]) +{ + int *type = atom->type; + int itype, jtype; + itype = type[i]; + jtype = type[j]; + + double qr,gr,g1r,q1r,q2r,ra; + double epd,epq1,epq2; + double eij_si,eij_sj,si_sj; + double eij_si_2,eij_sj_2,eij_si_3,eij_sj_3; + + // compute Neel's functions + + ra = rsq/g3[itype][jtype]/g3[itype][jtype]; + gr = 4.0*g1[itype][jtype]*ra; + gr *= (1.0-g2[itype][jtype]*ra); + gr *= exp(-ra); + + ra = rsq/q3[itype][jtype]/q3[itype][jtype]; + qr = 4.0*q1[itype][jtype]*ra; + qr *= (1.0-q2[itype][jtype]*ra); + qr *= exp(-ra); + + g1r = (gr + 12.0*qr/35.0); + q1r = 9.0*qr/5.0; + q2r = -2.0*qr/5.0; + + eij_si = eij[0]*spi[0] + eij[1]*spi[1] + eij[2]*spi[2]; + eij_sj = eij[0]*spj[0] + eij[1]*spj[1] + eij[2]*spj[2]; + si_sj = spi[0]*spj[0] + spi[1]*spj[1] + spi[2]*spj[2]; + epd = g1r*(eij_si*eij_sj-si_sj/3.0); + eij_si_2 = eij_si*eij_si; + eij_sj_2 = eij_sj*eij_sj; + epq1 = q1r*(eij_si_2-si_sj/3.0)*(eij_sj_2-si_sj/3.0); + eij_si_3 = eij_si*eij_si*eij_si; + eij_sj_3 = eij_sj*eij_sj*eij_sj; + epq2 = q2r*(eij_si*eij_sj_3+eij_sj*eij_si_3); + + return (epd+epq1+epq2); +} + /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ diff --git a/src/SPIN/pair_spin_neel.h b/src/SPIN/pair_spin_neel.h index 5261a7f746..a39cf839c9 100644 --- a/src/SPIN/pair_spin_neel.h +++ b/src/SPIN/pair_spin_neel.h @@ -38,6 +38,7 @@ class PairSpinNeel : public PairSpin { void compute_neel(int, int, double, double *, double *, double *, double *); void compute_neel_mech(int, int, double, double *, double *, double *, double *); + double compute_neel_energy(int, int, double, double *, double *, double *); void write_restart(FILE *); void read_restart(FILE *); -- GitLab From a7878096f0e48c4fc9bce241094bc45225564462 Mon Sep 17 00:00:00 2001 From: julient31 Date: Mon, 17 Feb 2020 17:35:59 -0700 Subject: [PATCH 028/577] Commit2 JT 021720 - small change in energy - to do: check w and rework F --- src/SPIN/pair_spin_neel.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/SPIN/pair_spin_neel.cpp b/src/SPIN/pair_spin_neel.cpp index 811276cac5..6cf5d4843f 100644 --- a/src/SPIN/pair_spin_neel.cpp +++ b/src/SPIN/pair_spin_neel.cpp @@ -605,8 +605,8 @@ double PairSpinNeel::compute_neel_energy(int i, int j, double rsq, double eij[3] eij_si_2 = eij_si*eij_si; eij_sj_2 = eij_sj*eij_sj; epq1 = q1r*(eij_si_2-si_sj/3.0)*(eij_sj_2-si_sj/3.0); - eij_si_3 = eij_si*eij_si*eij_si; - eij_sj_3 = eij_sj*eij_sj*eij_sj; + eij_si_3 = eij_si*eij_si_2; + eij_sj_3 = eij_sj*eij_sj_2; epq2 = q2r*(eij_si*eij_sj_3+eij_sj*eij_si_3); return (epd+epq1+epq2); -- GitLab From b9a9bebd37e21692d8c732e47a2910794f9c3244 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Thu, 20 Feb 2020 12:48:44 -0700 Subject: [PATCH 029/577] delay change_box error check on per-atom restart data existing --- doc/src/change_box.rst | 40 ++++++++++++++++++++++++++++------------ src/change_box.cpp | 22 +++++++++++++++++++--- 2 files changed, 47 insertions(+), 15 deletions(-) diff --git a/doc/src/change_box.rst b/doc/src/change_box.rst index 02f06ac681..f481658849 100644 --- a/doc/src/change_box.rst +++ b/doc/src/change_box.rst @@ -147,24 +147,40 @@ new owning processors. .. note:: - The simulation box size/shape can be changed by arbitrarily - large amounts by this command. This is not a problem, except that the + The simulation box size/shape can be changed by arbitrarily large + amounts by this command. This is not a problem, except that the mapping of processors to the simulation box is not changed from its initial 3d configuration; see the :doc:`processors ` command. Thus, if the box size/shape changes dramatically, the - mapping of processors to the simulation box may not end up as optimal - as the initial mapping attempted to be. + mapping of processors to the simulation box may not end up as + optimal as the initial mapping attempted to be. You may wish to + re-balance the atoms by using the :doc:`balance ` command + if that is the case. .. note:: - Because the keywords used in this command are applied one at a - time to the simulation box and the atoms in it, care must be taken - with triclinic cells to avoid exceeding the limits on skew after each - transformation in the sequence. If skew is exceeded before the final - transformation this can be avoided by changing the order of the - sequence, or breaking the transformation into two or more smaller - transformations. For more information on the allowed limits for box - skew see the discussion on triclinic boxes on :doc:`Howto triclinic ` doc page. + You cannot use this command after reading a restart file (and + before a run is performed) if the restart file stored per-atom + information from a fix and any of the specified keywords change the + box size or shape or boundary conditions. This is because atoms + may be moved to new processors and the restart info will not + migrate with them. LAMMPS will generate an error if this could + happen. Only the *ortho* and *triclinic* keywords do not trigger + this error. One solution is to perform a "run 0" command before + using the change_box command. This clears the per-atom restart + data, whether it has been re-assigned to a new fix or not. + +.. note:: + + Because the keywords used in this command are applied one at a time + to the simulation box and the atoms in it, care must be taken with + triclinic cells to avoid exceeding the limits on skew after each + transformation in the sequence. If skew is exceeded before the + final transformation this can be avoided by changing the order of + the sequence, or breaking the transformation into two or more + smaller transformations. For more information on the allowed + limits for box skew see the discussion on triclinic boxes on + :doc:`Howto triclinic ` doc page. ---------- diff --git a/src/change_box.cpp b/src/change_box.cpp index 98119fb3bf..7ae49ca776 100644 --- a/src/change_box.cpp +++ b/src/change_box.cpp @@ -46,9 +46,6 @@ void ChangeBox::command(int narg, char **arg) if (domain->box_exist == 0) error->all(FLERR,"Change_box command before simulation box is defined"); if (narg < 2) error->all(FLERR,"Illegal change_box command"); - if (modify->nfix_restart_peratom) - error->all(FLERR,"Cannot change_box after " - "reading restart file with per-atom info"); if (comm->me == 0 && screen) fprintf(screen,"Changing box ...\n"); @@ -174,6 +171,21 @@ void ChangeBox::command(int narg, char **arg) if (nops == 0) error->all(FLERR,"Illegal change_box command"); + // move_atoms = 1 if need to move atoms to new procs after box changes + // anything other than ORTHO or TRICLINIC may cause atom movement + + int move_atoms = 0; + for (int m = 0; m < nops; m++) { + if (ops[m].style != ORTHO || ops[m].style != TRICLINIC) move_atoms = 1; + } + + // error if moving atoms and there is stored per-atom restart state + // disallowed b/c restart per-atom fix info will not move with atoms + + if (move_atoms && modify->nfix_restart_peratom) + error->all(FLERR,"Change_box parameter not allowed after " + "reading restart file with per-atom info"); + // read options from end of input line options(narg-iarg,&arg[iarg]); @@ -350,6 +362,10 @@ void ChangeBox::command(int narg, char **arg) if (domain->triclinic) domain->lamda2x(atom->nlocal); } + // done if don't need to move atoms + + if (!move_atoms) return; + // move atoms back inside simulation box and to new processors // use remap() instead of pbc() // in case box moved a long distance relative to atoms -- GitLab From 361f7bb0fd7e386d91a47436ec4dcf65a0b4eaac Mon Sep 17 00:00:00 2001 From: julient31 Date: Fri, 21 Feb 2020 12:07:42 -0700 Subject: [PATCH 030/577] Commit JT 022120 - added precession_spin management in compute_spin - to do: add it for pairs - make sure users only declare 1 precession/spin --- src/SPIN/compute_spin.cpp | 70 +++++++++++++++++++++++++++++++- src/SPIN/compute_spin.h | 14 +++++++ src/SPIN/fix_precession_spin.cpp | 10 +++++ src/SPIN/fix_precession_spin.h | 4 ++ 4 files changed, 96 insertions(+), 2 deletions(-) diff --git a/src/SPIN/compute_spin.cpp b/src/SPIN/compute_spin.cpp index 7ee2b5bcfc..0612e5720e 100644 --- a/src/SPIN/compute_spin.cpp +++ b/src/SPIN/compute_spin.cpp @@ -24,11 +24,15 @@ #include "compute_spin.h" #include #include +#include #include "atom.h" #include "error.h" +#include "fix_precession_spin.h" #include "force.h" #include "math_const.h" #include "memory.h" +#include "modify.h" +#include "pair_spin.h" #include "update.h" using namespace LAMMPS_NS; @@ -64,6 +68,50 @@ void ComputeSpin::init() { hbar = force->hplanck/MY_2PI; kb = force->boltz; + + // init length of vector of ptrs to Pair/Spin styles + + if (npairspin > 0) { + spin_pairs = new PairSpin*[npairspin]; + } + + // loop 2: fill vector with ptrs to Pair/Spin styles + + int count = 0; + if (npairspin == 1) { + count = 1; + spin_pairs[0] = (PairSpin *) force->pair_match("spin",0,0); + } else if (npairspin > 1) { + for (int i = 0; ipair_match("spin",0,i)) { + spin_pairs[count] = (PairSpin *) force->pair_match("spin",0,i); + count++; + } + } + } + + if (count != npairspin) + error->all(FLERR,"Incorrect number of spin pairs"); + + // set pair/spin and long/spin flags + + if (npairspin >= 1) pair_spin_flag = 1; + + for (int i = 0; ipair_match("spin/long",0,i)) { + long_spin_flag = 1; + } + } + + // ptrs FixPrecessionSpin classes + + int iforce; + for (iforce = 0; iforce < modify->nfix; iforce++) { + if (strstr(modify->fix[iforce]->style,"precession/spin")) { + precession_spin_flag = 1; + lockprecessionspin = (FixPrecessionSpin *) modify->fix[iforce]; + } + } } /* ---------------------------------------------------------------------- */ @@ -104,7 +152,24 @@ void ComputeSpin::compute_vector() mag[0] += sp[i][0]; mag[1] += sp[i][1]; mag[2] += sp[i][2]; - magenergy -= (sp[i][0]*fm[i][0] + sp[i][1]*fm[i][1] + sp[i][2]*fm[i][2]); + // magenergy -= (sp[i][0]*fm[i][0] + sp[i][1]*fm[i][1] + sp[i][2]*fm[i][2]); + + // update magnetic precession energies + + if (precession_spin_flag) { + magenergy -= lockprecessionspin->compute_zeeman_energy(sp[i]); + magenergy -= lockprecessionspin->compute_anisotropy_energy(sp[i]); + magenergy -= lockprecessionspin->compute_cubic_energy(sp[i]); + } + + // update magnetic pair interactions + + if (pair_spin_flag) { + for (int k = 0; k < npairspin; k++) { + // spin_pairs[k]->compute_single_pair(i,fmi); + } + } + tx = sp[i][1]*fm[i][2]-sp[i][2]*fm[i][1]; ty = sp[i][2]*fm[i][0]-sp[i][0]*fm[i][2]; tz = sp[i][0]*fm[i][1]-sp[i][1]*fm[i][0]; @@ -134,7 +199,8 @@ void ComputeSpin::compute_vector() vector[1] = magtot[1]; vector[2] = magtot[2]; vector[3] = magtot[3]; - vector[4] = magenergytot*hbar; + // vector[4] = magenergytot*hbar; + vector[4] = magenergytot; vector[5] = spintemperature; } diff --git a/src/SPIN/compute_spin.h b/src/SPIN/compute_spin.h index c5d55b84cb..2ff0ba8eee 100644 --- a/src/SPIN/compute_spin.h +++ b/src/SPIN/compute_spin.h @@ -32,7 +32,21 @@ class ComputeSpin : public Compute { void compute_vector(); private: + int pair_spin_flag; // magnetic pair flags + int long_spin_flag; // magnetic long-range flag + int precession_spin_flag; // magnetic precession flags + double kb,hbar; + + // pointers to magnetic fixes + + class FixPrecessionSpin *lockprecessionspin; + + // pointers to magnetic pair styles + + int npairs, npairspin; // # of pairs, and # of spin pairs + class Pair *pair; + class PairSpin **spin_pairs; // vector of spin pairs void allocate(); }; diff --git a/src/SPIN/fix_precession_spin.cpp b/src/SPIN/fix_precession_spin.cpp index 2d55de33ea..f9307d7ad0 100644 --- a/src/SPIN/fix_precession_spin.cpp +++ b/src/SPIN/fix_precession_spin.cpp @@ -302,6 +302,16 @@ void FixPrecessionSpin::compute_zeeman(int i, double fmi[3]) /* ---------------------------------------------------------------------- */ +double FixPrecessionSpin::compute_zeeman_energy(double spi[4]) +{ + double energy = 0.0; + double scalar = nhx*spi[0]+nhy*spi[1]+nhz*spi[2]; + energy = hbar*H_field*spi[3]*scalar; + return energy; +} + +/* ---------------------------------------------------------------------- */ + void FixPrecessionSpin::compute_anisotropy(double spi[3], double fmi[3]) { double scalar = nax*spi[0] + nay*spi[1] + naz*spi[2]; diff --git a/src/SPIN/fix_precession_spin.h b/src/SPIN/fix_precession_spin.h index 6ece653ca7..3c809506c1 100644 --- a/src/SPIN/fix_precession_spin.h +++ b/src/SPIN/fix_precession_spin.h @@ -41,7 +41,11 @@ class FixPrecessionSpin : public Fix { int zeeman_flag, aniso_flag, cubic_flag; void compute_single_precession(int, double *, double *); + + // zeeman calculations + void compute_zeeman(int, double *); + double compute_zeeman_energy(double *); // uniaxial aniso calculations -- GitLab From 09d0df43e215e6ce646334b5b60c3e8e53ff85f0 Mon Sep 17 00:00:00 2001 From: julient31 Date: Fri, 21 Feb 2020 17:53:14 -0700 Subject: [PATCH 031/577] Commit JT 022120 - added message for only one precession/spin (+doc) - added a per pair/spin class emag table --- doc/src/fix_precession_spin.rst | 7 +++++- src/SPIN/compute_spin.cpp | 18 +++++++++++++- src/SPIN/fix_precession_spin.cpp | 9 +++++++ src/SPIN/pair_spin.cpp | 6 +++++ src/SPIN/pair_spin.h | 4 +++ src/SPIN/pair_spin_dipole_cut.cpp | 10 ++++++++ src/SPIN/pair_spin_dipole_long.cpp | 24 ++++++++++++++---- src/SPIN/pair_spin_dmi.cpp | 15 ++++++++++- src/SPIN/pair_spin_exchange.cpp | 40 ++++++++++++++++++++++++++++++ src/SPIN/pair_spin_exchange.h | 2 ++ src/SPIN/pair_spin_magelec.cpp | 14 +++++++++++ src/SPIN/pair_spin_neel.cpp | 14 +++++++++++ 12 files changed, 155 insertions(+), 8 deletions(-) diff --git a/doc/src/fix_precession_spin.rst b/doc/src/fix_precession_spin.rst index 9cd15119bd..2d23ed1037 100644 --- a/doc/src/fix_precession_spin.rst +++ b/doc/src/fix_precession_spin.rst @@ -82,6 +82,7 @@ function for the same parameters. .. image:: JPG/zeeman_langevin.jpg :align: center + :width: 600 The temperature effects are accounted for by connecting the spin :math:`i` to a thermal bath using a Langevin thermostat (see @@ -159,11 +160,15 @@ No information about this fix is written to :doc:`binary restart files Restrictions """""""""""" - The *precession/spin* style is part of the SPIN package. This style is only enabled if LAMMPS was built with this package, and if the atom\_style "spin" was declared. See the :doc:`Build package ` doc page for more info. +The *precession/spin* style can only be declared once. If more +than one precession type (for example combining an anisotropy and a Zeeman interactions) +has to be declared, they have to be chained in the same command +line (as shown in the examples above). + Related commands """""""""""""""" diff --git a/src/SPIN/compute_spin.cpp b/src/SPIN/compute_spin.cpp index 0612e5720e..8a71be019b 100644 --- a/src/SPIN/compute_spin.cpp +++ b/src/SPIN/compute_spin.cpp @@ -69,6 +69,22 @@ void ComputeSpin::init() hbar = force->hplanck/MY_2PI; kb = force->boltz; + // loop 1: obtain # of Pairs, and # of Pair/Spin styles + + if (force->pair_match("spin",0,0)) { // only one Pair/Spin style + pair = force->pair_match("spin",0,0); + npairs = pair->instance_total; + npairspin = 1; + } else if (force->pair_match("spin",0,1)) { // more than one Pair/Spin style + pair = force->pair_match("spin",0,1); + npairs = pair->instance_total; + for (int i = 0; ipair_match("spin",0,i)) { + npairspin ++; + } + } + } + // init length of vector of ptrs to Pair/Spin styles if (npairspin > 0) { @@ -166,7 +182,7 @@ void ComputeSpin::compute_vector() if (pair_spin_flag) { for (int k = 0; k < npairspin; k++) { - // spin_pairs[k]->compute_single_pair(i,fmi); + magenergy += spin_pairs[k]->emag[i]; } } diff --git a/src/SPIN/fix_precession_spin.cpp b/src/SPIN/fix_precession_spin.cpp index f9307d7ad0..57e4549718 100644 --- a/src/SPIN/fix_precession_spin.cpp +++ b/src/SPIN/fix_precession_spin.cpp @@ -197,6 +197,15 @@ void FixPrecessionSpin::init() error->all(FLERR,"Illegal precession/spin command"); } + // check that fix precession/spin is only declared once + + int iprec = 0; + for (int iforce = 0; iforce < modify->nfix; iforce++) + if (strstr(modify->fix[iforce]->style,"precession/spin")) iprec++; + if (iprec > 1) + error->all(FLERR,"precession/spin command can only be declared once"); + + varflag = CONSTANT; if (magfieldstyle != CONSTANT) varflag = EQUAL; diff --git a/src/SPIN/pair_spin.cpp b/src/SPIN/pair_spin.cpp index f167e3455c..01b8775eab 100644 --- a/src/SPIN/pair_spin.cpp +++ b/src/SPIN/pair_spin.cpp @@ -29,6 +29,7 @@ #include "fix.h" #include "force.h" #include "math_const.h" +#include "memory.h" #include "modify.h" #include "neighbor.h" #include "neigh_request.h" @@ -98,4 +99,9 @@ void PairSpin::init_style() if (ifix >=0) lattice_flag = ((FixNVESpin *) modify->fix[ifix])->lattice_flag; + // test emag list storing mag energies + // init. size of energy stacking lists + + nlocal_max = atom->nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); } diff --git a/src/SPIN/pair_spin.h b/src/SPIN/pair_spin.h index 34f12d8d59..c8292236a3 100644 --- a/src/SPIN/pair_spin.h +++ b/src/SPIN/pair_spin.h @@ -31,6 +31,10 @@ friend class FixNVESpin; virtual void compute(int, int) {} virtual void compute_single_pair(int, double *) {} + + // test emag list storing mag energies + int nlocal_max; // max value of nlocal (for size of lists) + double *emag; // energy list protected: double hbar; // Planck constant (eV.ps.rad-1) diff --git a/src/SPIN/pair_spin_dipole_cut.cpp b/src/SPIN/pair_spin_dipole_cut.cpp index a7372b480d..6029f8bdbb 100644 --- a/src/SPIN/pair_spin_dipole_cut.cpp +++ b/src/SPIN/pair_spin_dipole_cut.cpp @@ -64,6 +64,9 @@ PairSpinDipoleCut::~PairSpinDipoleCut() memory->destroy(setflag); memory->destroy(cut_spin_long); memory->destroy(cutsq); + + // test emag list storing mag energies + memory->destroy(emag); } } @@ -185,6 +188,13 @@ void PairSpinDipoleCut::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + // computation of the exchange interaction // loop over atoms and their neighbors diff --git a/src/SPIN/pair_spin_dipole_long.cpp b/src/SPIN/pair_spin_dipole_long.cpp index 124522a9b9..7856035159 100644 --- a/src/SPIN/pair_spin_dipole_long.cpp +++ b/src/SPIN/pair_spin_dipole_long.cpp @@ -69,6 +69,9 @@ PairSpinDipoleLong::~PairSpinDipoleLong() memory->destroy(setflag); memory->destroy(cut_spin_long); memory->destroy(cutsq); + + // test emag list storing mag energies + memory->destroy(emag); } } @@ -212,6 +215,13 @@ void PairSpinDipoleLong::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + pre1 = 2.0 * g_ewald / MY_PIS; pre2 = 4.0 * pow(g_ewald,3.0) / MY_PIS; pre3 = 8.0 * pow(g_ewald,5.0) / MY_PIS; @@ -221,16 +231,20 @@ void PairSpinDipoleLong::compute(int eflag, int vflag) for (ii = 0; ii < inum; ii++) { i = ilist[ii]; + itype = type[i]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; xi[0] = x[i][0]; xi[1] = x[i][1]; xi[2] = x[i][2]; - jlist = firstneigh[i]; - jnum = numneigh[i]; spi[0] = sp[i][0]; spi[1] = sp[i][1]; spi[2] = sp[i][2]; spi[3] = sp[i][3]; - itype = type[i]; + + // test emag list storing mag energies + emag[i] = 0.0; for (jj = 0; jj < jnum; jj++) { j = jlist[jj]; @@ -294,9 +308,9 @@ void PairSpinDipoleLong::compute(int eflag, int vflag) if (eflag) { if (rsq <= local_cut2) { - evdwl -= spi[0]*fmi[0] + spi[1]*fmi[1] + - spi[2]*fmi[2]; + evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); evdwl *= 0.5*hbar; + emag[i] += evdwl; } } else evdwl = 0.0; diff --git a/src/SPIN/pair_spin_dmi.cpp b/src/SPIN/pair_spin_dmi.cpp index 04c2dc408d..266bc05da4 100644 --- a/src/SPIN/pair_spin_dmi.cpp +++ b/src/SPIN/pair_spin_dmi.cpp @@ -53,6 +53,9 @@ PairSpinDmi::~PairSpinDmi() memory->destroy(vmech_dmy); memory->destroy(vmech_dmz); memory->destroy(cutsq); + + // test emag list storing mag energies + memory->destroy(emag); } } @@ -191,6 +194,13 @@ void PairSpinDmi::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + // dmi computation // loop over all atoms @@ -206,7 +216,9 @@ void PairSpinDmi::compute(int eflag, int vflag) spi[0] = sp[i][0]; spi[1] = sp[i][1]; spi[2] = sp[i][2]; - + + // test emag list storing mag energies + emag[i] = 0.0; // loop on neighbors @@ -260,6 +272,7 @@ void PairSpinDmi::compute(int eflag, int vflag) if (eflag) { evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); evdwl *= 0.5*hbar; + emag[i] += evdwl; } else evdwl = 0.0; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, diff --git a/src/SPIN/pair_spin_exchange.cpp b/src/SPIN/pair_spin_exchange.cpp index 6eacb04ee3..d645515506 100644 --- a/src/SPIN/pair_spin_exchange.cpp +++ b/src/SPIN/pair_spin_exchange.cpp @@ -50,6 +50,9 @@ PairSpinExchange::~PairSpinExchange() memory->destroy(J2); memory->destroy(J3); memory->destroy(cutsq); // to be implemented + + // test emag list storing mag energies + memory->destroy(emag); } } @@ -176,6 +179,13 @@ void PairSpinExchange::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + // computation of the exchange interaction // loop over atoms and their neighbors @@ -191,6 +201,9 @@ void PairSpinExchange::compute(int eflag, int vflag) spi[0] = sp[i][0]; spi[1] = sp[i][1]; spi[2] = sp[i][2]; + + // test emag list storing mag energies + emag[i] = 0.0; // loop on neighbors @@ -243,6 +256,10 @@ void PairSpinExchange::compute(int eflag, int vflag) if (eflag) { evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); evdwl *= 0.5*hbar; + // printf("test ex energy: %g \n",evdwl); + // evdwl = -0.5*compute_energy(i,j,rsq,spi,spj); + // printf("test ex energy: %g \n",evdwl); + emag[i] += evdwl; // evdwl *= hbar; } else evdwl = 0.0; @@ -385,6 +402,29 @@ void PairSpinExchange::compute_exchange_mech(int i, int j, double rsq, double ei fi[2] -= Jex_mech*eij[2]; } +/* ---------------------------------------------------------------------- + compute energy of spin pair i and j +------------------------------------------------------------------------- */ + +// double PairSpinExchange::compute_energy(int i, int j, double rsq, double spi[3], double spj[3]) +// { +// int *type = atom->type; +// int itype, jtype; +// double Jex, ra; +// double energy = 0.0; +// itype = type[i]; +// jtype = type[j]; +// +// Jex = J1_mech[itype][jtype]; +// ra = rsq/J3[itype][jtype]/J3[itype][jtype]; +// Jex = 4.0*Jex*ra; +// Jex *= (1.0-J2[itype][jtype]*ra); +// Jex *= exp(-ra); +// +// energy = Jex*(spi[0]*spj[0]+spi[1]*spj[1]+spi[2]*spj[2]); +// return energy; +// } + /* ---------------------------------------------------------------------- allocate all arrays ------------------------------------------------------------------------- */ diff --git a/src/SPIN/pair_spin_exchange.h b/src/SPIN/pair_spin_exchange.h index 19eafeb5ca..4e9e6bfac8 100644 --- a/src/SPIN/pair_spin_exchange.h +++ b/src/SPIN/pair_spin_exchange.h @@ -39,6 +39,8 @@ class PairSpinExchange : public PairSpin { void compute_exchange(int, int, double, double *, double *); void compute_exchange_mech(int, int, double, double *, double *, double *, double *); + // double compute_energy(int , int , double , double *, double *); + void write_restart(FILE *); void read_restart(FILE *); void write_restart_settings(FILE *); diff --git a/src/SPIN/pair_spin_magelec.cpp b/src/SPIN/pair_spin_magelec.cpp index fabad4ae4d..ef91ab764a 100644 --- a/src/SPIN/pair_spin_magelec.cpp +++ b/src/SPIN/pair_spin_magelec.cpp @@ -51,6 +51,9 @@ PairSpinMagelec::~PairSpinMagelec() memory->destroy(v_mey); memory->destroy(v_mez); memory->destroy(cutsq); // to be deteled + + // test emag list storing mag energies + memory->destroy(emag); } } @@ -185,6 +188,13 @@ void PairSpinMagelec::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + // magneto-electric computation // loop over atoms and their neighbors @@ -200,6 +210,9 @@ void PairSpinMagelec::compute(int eflag, int vflag) spi[0] = sp[i][0]; spi[1] = sp[i][1]; spi[2] = sp[i][2]; + + // test emag list storing mag energies + emag[i] = 0.0; // loop on neighbors @@ -252,6 +265,7 @@ void PairSpinMagelec::compute(int eflag, int vflag) if (eflag) { evdwl -= (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); evdwl *= 0.5*hbar; + emag[i] += evdwl; } else evdwl = 0.0; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, diff --git a/src/SPIN/pair_spin_neel.cpp b/src/SPIN/pair_spin_neel.cpp index 6cf5d4843f..e158906b75 100644 --- a/src/SPIN/pair_spin_neel.cpp +++ b/src/SPIN/pair_spin_neel.cpp @@ -54,6 +54,9 @@ PairSpinNeel::~PairSpinNeel() memory->destroy(q2); memory->destroy(q3); memory->destroy(cutsq); // to be deleted + + // test emag list storing mag energies + memory->destroy(emag); } } @@ -190,6 +193,13 @@ void PairSpinNeel::compute(int eflag, int vflag) numneigh = list->numneigh; firstneigh = list->firstneigh; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + // computation of the neel interaction // loop over atoms and their neighbors @@ -206,6 +216,9 @@ void PairSpinNeel::compute(int eflag, int vflag) spi[1] = sp[i][1]; spi[2] = sp[i][2]; + // test emag list storing mag energies + emag[i] = 0.0; + // loop on neighbors for (jj = 0; jj < jnum; jj++) { @@ -262,6 +275,7 @@ void PairSpinNeel::compute(int eflag, int vflag) // evdwl = (spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); evdwl = compute_neel_energy(i,j,rsq,eij,spi,spj); evdwl *= 0.5*hbar; + emag[i] += evdwl; } else evdwl = 0.0; if (evflag) ev_tally_xyz(i,j,nlocal,newton_pair, -- GitLab From 674781fe0e77828cbb2a946670e55103451f7c55 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 24 Feb 2020 13:27:40 -0700 Subject: [PATCH 032/577] Add Kokkos version of compute orientorder/atom --- cmake/Modules/Packages/USER-PLUMED.cmake | 4 +- doc/Makefile | 3 + doc/lammps.1 | 11 +- doc/src/Build_extras.rst | 14 +- doc/src/Build_windows.rst | 28 +- doc/src/Eqs/centro_symmetry.jpg | Bin 4111 -> 0 bytes doc/src/Eqs/centro_symmetry.tex | 9 - doc/src/Eqs/cna_cutoff1.jpg | Bin 13431 -> 0 bytes doc/src/Eqs/cna_cutoff1.tex | 14 - doc/src/Eqs/cna_cutoff2.jpg | Bin 2518 -> 0 bytes doc/src/Eqs/cna_cutoff2.tex | 12 - doc/src/Eqs/cnp_cutoff.jpg | Bin 13431 -> 0 bytes doc/src/Eqs/cnp_cutoff.tex | 14 - doc/src/Eqs/cnp_cutoff2.jpg | Bin 2518 -> 0 bytes doc/src/Eqs/cnp_cutoff2.tex | 12 - doc/src/Eqs/cnp_eq.jpg | Bin 23959 -> 0 bytes doc/src/Eqs/cnp_eq.tex | 9 - doc/src/Eqs/compute_dpd.jpg | Bin 21381 -> 0 bytes doc/src/Eqs/compute_dpd.tex | 13 - doc/src/Eqs/compute_fep_bar.jpg | Bin 18106 -> 0 bytes doc/src/Eqs/compute_fep_bar.tex | 7 - doc/src/Eqs/compute_fep_fdti.jpg | Bin 15544 -> 0 bytes doc/src/Eqs/compute_fep_fdti.tex | 10 - doc/src/Eqs/compute_fep_fep.jpg | Bin 18055 -> 0 bytes doc/src/Eqs/compute_fep_fep.tex | 9 - doc/src/Eqs/compute_fep_lambda.jpg | Bin 10511 -> 0 bytes doc/src/Eqs/compute_fep_lambda.tex | 10 - doc/src/Eqs/compute_fep_ti.jpg | Bin 18149 -> 0 bytes doc/src/Eqs/compute_fep_ti.tex | 10 - doc/src/Eqs/compute_fep_u.jpg | Bin 9337 -> 0 bytes doc/src/Eqs/compute_fep_u.tex | 7 - doc/src/Eqs/compute_fep_vol.jpg | Bin 15209 -> 0 bytes doc/src/Eqs/compute_fep_vol.tex | 9 - doc/src/Eqs/compute_gyration.jpg | Bin 3658 -> 0 bytes doc/src/Eqs/compute_gyration.tex | 9 - doc/src/Eqs/compute_msd_nongauss.jpg | Bin 7277 -> 0 bytes doc/src/Eqs/compute_msd_nongauss.tex | 9 - doc/src/Eqs/compute_saed1.jpg | Bin 1471 -> 0 bytes doc/src/Eqs/compute_saed1.tex | 10 - doc/src/Eqs/compute_saed2.jpg | Bin 4911 -> 0 bytes doc/src/Eqs/compute_saed2.tex | 9 - doc/src/Eqs/compute_saed3.jpg | Bin 7048 -> 0 bytes doc/src/Eqs/compute_saed3.tex | 10 - doc/src/Eqs/compute_shape_parameters.jpg | Bin 7007 -> 0 bytes doc/src/Eqs/compute_shape_parameters.tex | 13 - doc/src/Eqs/compute_sna_atom1.jpg | Bin 19001 -> 0 bytes doc/src/Eqs/compute_sna_atom1.tex | 11 - doc/src/Eqs/compute_sna_atom2.jpg | Bin 17114 -> 0 bytes doc/src/Eqs/compute_sna_atom2.tex | 11 - doc/src/Eqs/compute_sna_atom3.jpg | Bin 19644 -> 0 bytes doc/src/Eqs/compute_sna_atom3.tex | 16 - doc/src/Eqs/compute_sna_atom4.jpg | Bin 35933 -> 0 bytes doc/src/Eqs/compute_sna_atom4.tex | 14 - doc/src/Eqs/compute_sna_atom5.jpg | Bin 14734 -> 0 bytes doc/src/Eqs/compute_sna_atom5.tex | 12 - doc/src/Eqs/compute_sna_atom6.jpg | Bin 17274 -> 0 bytes doc/src/Eqs/compute_sna_atom6.tex | 12 - doc/src/Eqs/compute_xrd1.jpg | Bin 2363 -> 0 bytes doc/src/Eqs/compute_xrd1.tex | 10 - doc/src/Eqs/compute_xrd2.jpg | Bin 4778 -> 0 bytes doc/src/Eqs/compute_xrd2.tex | 9 - doc/src/Eqs/compute_xrd3.jpg | Bin 4745 -> 0 bytes doc/src/Eqs/compute_xrd3.tex | 9 - doc/src/Eqs/compute_xrd4.jpg | Bin 2278 -> 0 bytes doc/src/Eqs/compute_xrd4.tex | 9 - doc/src/Eqs/compute_xrd5.jpg | Bin 7603 -> 0 bytes doc/src/Eqs/compute_xrd5.tex | 10 - doc/src/Eqs/fix_bond_react.jpg | Bin 2427 -> 0 bytes doc/src/Eqs/fix_bond_react.tex | 9 - doc/src/Eqs/fix_box_relax1.jpg | Bin 3375 -> 0 bytes doc/src/Eqs/fix_box_relax1.tex | 9 - doc/src/Eqs/fix_box_relax2.jpg | Bin 3029 -> 0 bytes doc/src/Eqs/fix_box_relax2.tex | 9 - doc/src/Eqs/fix_controller1.jpg | Bin 4832 -> 0 bytes doc/src/Eqs/fix_controller1.tex | 12 - doc/src/Eqs/fix_controller2.jpg | Bin 5571 -> 0 bytes doc/src/Eqs/fix_controller2.tex | 12 - doc/src/Eqs/fix_ehex_eom.jpg | Bin 3272 -> 0 bytes doc/src/Eqs/fix_ehex_eom.tex | 8 - doc/src/Eqs/fix_ehex_f.jpg | Bin 10352 -> 0 bytes doc/src/Eqs/fix_ehex_f.tex | 12 - doc/src/Eqs/fix_eos-cv.jpg | Bin 3016 -> 0 bytes doc/src/Eqs/fix_eos-cv.tex | 9 - doc/src/Eqs/fix_eos_table_rx.jpg | Bin 17367 -> 0 bytes doc/src/Eqs/fix_eos_table_rx.tex | 9 - doc/src/Eqs/fix_gcmc1.jpg | Bin 5617 -> 0 bytes doc/src/Eqs/fix_gcmc1.tex | 9 - doc/src/Eqs/fix_gcmc2.jpg | Bin 10626 -> 0 bytes doc/src/Eqs/fix_gcmc2.tex | 10 - doc/src/Eqs/fix_gcmc3.jpg | Bin 7437 -> 0 bytes doc/src/Eqs/fix_gcmc3.tex | 9 - doc/src/Eqs/fix_gld1.jpg | Bin 14274 -> 0 bytes doc/src/Eqs/fix_gld1.tex | 13 - doc/src/Eqs/fix_grem.jpg | Bin 6224 -> 0 bytes doc/src/Eqs/fix_grem.tex | 9 - .../fix_integration_spin_stdecomposition.tex | 40 - doc/src/Eqs/fix_lb_fluid_boltzmann.jpg | Bin 4643 -> 0 bytes doc/src/Eqs/fix_lb_fluid_boltzmann.tex | 14 - doc/src/Eqs/fix_lb_fluid_fluidforce.jpg | Bin 2358 -> 0 bytes doc/src/Eqs/fix_lb_fluid_fluidforce.tex | 14 - doc/src/Eqs/fix_lb_fluid_gammadefault.jpg | Bin 4793 -> 0 bytes doc/src/Eqs/fix_lb_fluid_gammadefault.tex | 14 - doc/src/Eqs/fix_lb_fluid_navierstokes.jpg | Bin 9311 -> 0 bytes doc/src/Eqs/fix_lb_fluid_navierstokes.tex | 16 - doc/src/Eqs/fix_lb_fluid_properties.jpg | Bin 3471 -> 0 bytes doc/src/Eqs/fix_lb_fluid_properties.tex | 17 - doc/src/Eqs/fix_lb_fluid_stress.jpg | Bin 2530 -> 0 bytes doc/src/Eqs/fix_lb_fluid_stress.tex | 14 - doc/src/Eqs/fix_lb_fluid_viscosity.jpg | Bin 6522 -> 0 bytes doc/src/Eqs/fix_lb_fluid_viscosity.tex | 14 - doc/src/Eqs/fix_mvv_dpd.jpg | Bin 26880 -> 0 bytes doc/src/Eqs/fix_mvv_dpd.tex | 21 - doc/src/Eqs/fix_nh1.jpg | Bin 68243 -> 0 bytes doc/src/Eqs/fix_nh1.tex | 36 - doc/src/Eqs/fix_nphug.jpg | Bin 7506 -> 0 bytes doc/src/Eqs/fix_nphug.tex | 9 - doc/src/Eqs/fix_orient_fcc.jpg | Bin 26005 -> 0 bytes doc/src/Eqs/fix_orient_fcc.tex | 30 - doc/src/Eqs/fix_pimd.jpg | Bin 14569 -> 0 bytes doc/src/Eqs/fix_pimd.tex | 17 - doc/src/Eqs/fix_rattle_constraints.jpg | Bin 4556 -> 0 bytes doc/src/Eqs/fix_rattle_constraints.tex | 9 - doc/src/Eqs/fix_rattle_rij.jpg | Bin 1812 -> 0 bytes doc/src/Eqs/fix_rattle_rij.tex | 8 - doc/src/Eqs/fix_rhok.jpg | Bin 18330 -> 0 bytes doc/src/Eqs/fix_rhok.tex | 11 - doc/src/Eqs/fix_rx.jpg | Bin 2427 -> 0 bytes doc/src/Eqs/fix_rx.tex | 9 - doc/src/Eqs/fix_rx_localTemp.jpg | Bin 16562 -> 0 bytes doc/src/Eqs/fix_rx_localTemp.tex | 9 - doc/src/Eqs/fix_rx_localTemp2.jpg | Bin 16284 -> 0 bytes doc/src/Eqs/fix_rx_localTemp2.tex | 9 - doc/src/Eqs/fix_rx_reaction.jpg | Bin 2896 -> 0 bytes doc/src/Eqs/fix_rx_reaction.tex | 9 - doc/src/Eqs/fix_rx_reactionRate.jpg | Bin 2939 -> 0 bytes doc/src/Eqs/fix_rx_reactionRate.tex | 9 - doc/src/Eqs/fix_spring_rg.jpg | Bin 16204 -> 0 bytes doc/src/Eqs/fix_spring_rg.tex | 19 - doc/src/Eqs/fix_ttm.jpg | Bin 5869 -> 0 bytes doc/src/Eqs/fix_ttm.tex | 15 - doc/src/Eqs/fix_ttm_blast.jpg | Bin 4449 -> 0 bytes doc/src/Eqs/fix_ttm_blast.tex | 13 - doc/src/Eqs/fix_ttm_blast1.jpg | Bin 8657 -> 0 bytes doc/src/Eqs/fix_ttm_blast1.tex | 13 - doc/src/Eqs/fix_ttm_ce.jpg | Bin 7446 -> 0 bytes doc/src/Eqs/fix_ttm_ce.tex | 13 - doc/src/Eqs/fix_ttm_mod.jpg | Bin 10179 -> 0 bytes doc/src/Eqs/fix_ttm_mod.tex | 15 - doc/src/Eqs/fix_wall_colloid.jpg | Bin 17879 -> 0 bytes doc/src/Eqs/fix_wall_colloid.tex | 14 - doc/src/Eqs/fix_wall_ees.jpg | Bin 106786 -> 0 bytes doc/src/Eqs/fix_wall_ees.tex | 10 - doc/src/Eqs/fix_wall_harmonic.jpg | Bin 2413 -> 0 bytes doc/src/Eqs/fix_wall_harmonic.tex | 9 - doc/src/Eqs/fix_wall_lj1043.jpg | Bin 10996 -> 0 bytes doc/src/Eqs/fix_wall_lj1043.tex | 12 - doc/src/Eqs/fix_wall_lj93.jpg | Bin 4883 -> 0 bytes doc/src/Eqs/fix_wall_lj93.tex | 11 - doc/src/Eqs/hexorder.jpg | Bin 16870 -> 0 bytes doc/src/Eqs/hexorder.tex | 8 - doc/src/Eqs/orientorder.jpg | Bin 34695 -> 0 bytes doc/src/Eqs/orientorder.tex | 12 - doc/src/Eqs/pair_adp.jpg | Bin 20391 -> 0 bytes doc/src/Eqs/pair_adp.tex | 16 - doc/src/Eqs/pair_agni.jpg | Bin 15178 -> 0 bytes doc/src/Eqs/pair_agni.tex | 18 - doc/src/Eqs/pair_airebo.jpg | Bin 9380 -> 0 bytes doc/src/Eqs/pair_airebo.tex | 11 - doc/src/Eqs/pair_atm.jpg | Bin 5474 -> 0 bytes doc/src/Eqs/pair_atm.tex | 9 - doc/src/Eqs/pair_beck.jpg | Bin 9451 -> 0 bytes doc/src/Eqs/pair_beck.tex | 11 - doc/src/Eqs/pair_body_rounded.jpg | Bin 146978 -> 0 bytes doc/src/Eqs/pair_body_rounded.tex | 13 - doc/src/Eqs/pair_coul_soft.jpg | Bin 11309 -> 0 bytes doc/src/Eqs/pair_coul_soft.tex | 10 - doc/src/Eqs/pair_lj_soft.jpg | Bin 17984 -> 0 bytes doc/src/Eqs/pair_lj_soft.tex | 15 - doc/src/Eqs/pair_morse_soft.jpg | Bin 20988 -> 0 bytes doc/src/Eqs/pair_morse_soft.tex | 13 - doc/src/Eqs/pair_nm.jpg | Bin 6304 -> 0 bytes doc/src/Eqs/pair_nm.tex | 10 - doc/src/Eqs/pair_srp1.jpg | Bin 3537 -> 0 bytes doc/src/Eqs/pair_srp1.tex | 9 - doc/src/Eqs/pair_srp2.jpg | Bin 5648 -> 0 bytes doc/src/Eqs/pair_srp2.tex | 10 - doc/src/Eqs/pair_sw.jpg | Bin 28707 -> 0 bytes doc/src/Eqs/pair_sw.tex | 18 - doc/src/Eqs/pair_tersoff.jpg | Bin 36139 -> 0 bytes doc/src/Eqs/pair_tersoff_1.jpg | Bin 36584 -> 0 bytes doc/src/Eqs/pair_tersoff_1.tex | 24 - doc/src/Eqs/pair_tersoff_2.jpg | Bin 13756 -> 0 bytes doc/src/Eqs/pair_tersoff_2.tex | 14 - doc/src/Eqs/pair_tersoff_mod.jpg | Bin 91727 -> 0 bytes doc/src/Eqs/pair_tersoff_mod.tex | 24 - doc/src/Eqs/pair_tersoff_mod_c.jpg | Bin 4211 -> 0 bytes doc/src/Eqs/pair_tersoff_mod_c.tex | 10 - doc/src/Eqs/pair_tersoff_zbl.jpg | Bin 392677 -> 0 bytes doc/src/Eqs/pair_tersoff_zbl.tex | 33 - doc/src/Eqs/pair_ufm.jpg | Bin 17830 -> 0 bytes doc/src/Eqs/pair_ufm.tex | 14 - doc/src/Eqs/pair_vashishta.jpg | Bin 73306 -> 0 bytes doc/src/Eqs/pair_vashishta.tex | 22 - doc/src/Eqs/pair_yukawa.jpg | Bin 2189 -> 0 bytes doc/src/Eqs/pair_yukawa.tex | 9 - doc/src/Eqs/pair_yukawa_colloid.jpg | Bin 3067 -> 0 bytes doc/src/Eqs/pair_yukawa_colloid.tex | 9 - doc/src/Eqs/pair_zbl.jpg | Bin 32209 -> 0 bytes doc/src/Eqs/pair_zbl.tex | 11 - doc/src/Eqs/pressure.jpg | Bin 4333 -> 0 bytes doc/src/Eqs/pressure.tex | 9 - doc/src/Eqs/pressure_tensor.jpg | Bin 5457 -> 0 bytes doc/src/Eqs/pressure_tensor.tex | 10 - doc/src/Eqs/ptm_rmsd.jpg | Bin 6833 -> 0 bytes doc/src/Eqs/ptm_rmsd.tex | 21 - doc/src/Install_linux.rst | 25 +- .../fix_integration_spin_stdecomposition.jpg | Bin doc/src/compute_centro_atom.rst | 39 +- doc/src/compute_cna_atom.rst | 17 +- doc/src/compute_cnp_atom.rst | 32 +- doc/src/compute_dpd.rst | 24 +- doc/src/compute_dpd_atom.rst | 18 +- doc/src/compute_entropy_atom.rst | 26 +- doc/src/compute_fep.rst | 56 +- doc/src/compute_gyration.rst | 35 +- doc/src/compute_gyration_chunk.rst | 20 +- doc/src/compute_gyration_shape.rst | 10 +- doc/src/compute_gyration_shape_chunk.rst | 10 +- doc/src/compute_hexorder_atom.rst | 33 +- doc/src/compute_msd_nongauss.rst | 6 +- doc/src/compute_orientorder_atom.rst | 74 +- doc/src/compute_pressure.rst | 13 +- doc/src/compute_ptm_atom.rst | 7 +- doc/src/compute_saed.rst | 140 +++- doc/src/compute_sna_atom.rst | 44 +- doc/src/compute_xrd.rst | 27 +- doc/src/fix_ave_correlate_long.rst | 23 +- doc/src/fix_bond_react.rst | 10 +- doc/src/fix_box_relax.rst | 25 +- doc/src/fix_controller.rst | 48 +- doc/src/fix_ehex.rst | 15 +- doc/src/fix_eos_cv.rst | 18 +- doc/src/fix_eos_table_rx.rst | 55 +- doc/src/fix_gcmc.rst | 46 +- doc/src/fix_gld.rst | 10 +- doc/src/fix_grem.rst | 38 +- doc/src/fix_hyper_global.rst | 84 ++- doc/src/fix_hyper_local.rst | 243 +++--- doc/src/fix_langevin_spin.rst | 15 +- doc/src/fix_lb_fluid.rst | 89 ++- doc/src/fix_mvv_dpd.rst | 10 +- doc/src/fix_nh.rst | 25 +- doc/src/fix_nphug.rst | 51 +- doc/src/fix_npt_cauchy.rst | 22 +- doc/src/fix_nve_spin.rst | 2 +- doc/src/fix_orient.rst | 18 +- doc/src/fix_pimd.rst | 7 +- doc/src/fix_rhok.rst | 8 +- doc/src/fix_rx.rst | 32 +- doc/src/fix_shake.rst | 13 +- doc/src/fix_spring_rg.rst | 18 +- doc/src/fix_ti_spring.rst | 18 +- doc/src/fix_ttm.rst | 34 +- doc/src/fix_wall.rst | 47 +- doc/src/fix_wall_ees.rst | 41 +- doc/src/fix_wall_region.rst | 52 +- doc/src/min_style.rst | 16 +- doc/src/pair_adp.rst | 86 ++- doc/src/pair_agni.rst | 40 +- doc/src/pair_airebo.rst | 115 +-- doc/src/pair_atm.rst | 114 +-- doc/src/pair_beck.rst | 40 +- doc/src/pair_body_nparticle.rst | 30 +- doc/src/pair_body_rounded_polygon.rst | 61 +- doc/src/pair_body_rounded_polyhedron.rst | 55 +- doc/src/pair_fep_soft.rst | 224 +++--- doc/src/pair_nm.rst | 43 +- doc/src/pair_srp.rst | 34 +- doc/src/pair_sw.rst | 52 +- doc/src/pair_tersoff.rst | 65 +- doc/src/pair_tersoff_mod.rst | 83 ++- doc/src/pair_tersoff_zbl.rst | 86 ++- doc/src/pair_ufm.rst | 24 +- doc/src/pair_vashishta.rst | 62 +- doc/src/pair_yukawa.rst | 8 +- doc/src/pair_yukawa_colloid.rst | 26 +- doc/src/pair_zbl.rst | 35 +- doc/src/set.rst | 2 +- ....g++.1 => log.4Feb20.peptide-plumed.g++.1} | 34 +- ....g++.4 => log.4Feb20.peptide-plumed.g++.4} | 34 +- examples/USER/plumed/reference/p.log | 33 +- lib/gpu/lal_lj_tip4p_long.cpp | 25 +- lib/gpu/lal_lj_tip4p_long.cu | 326 +++++++- lib/plumed/Install.py | 4 +- lib/qmmm/Makefile.gfortran | 14 +- lib/qmmm/Makefile.ifort | 24 +- lib/qmmm/README | 13 +- src/GPU/pair_born_coul_long_gpu.cpp | 4 + src/GPU/pair_buck_coul_long_gpu.cpp | 4 + src/GPU/pair_lj_class2_coul_long_gpu.cpp | 4 + src/KOKKOS/Install.sh | 2 + .../compute_orientorder_atom_kokkos.cpp | 698 ++++++++++++++++++ src/KOKKOS/compute_orientorder_atom_kokkos.h | 150 ++++ src/KSPACE/pair_born_coul_long.cpp | 1 + src/KSPACE/pair_buck_long_coul_long.cpp | 1 + src/KSPACE/pair_coul_long.cpp | 1 + src/KSPACE/pair_lj_charmm_coul_long.cpp | 1 + src/KSPACE/pair_lj_charmmfsw_coul_long.cpp | 1 + src/KSPACE/pair_lj_cut_coul_long.cpp | 1 + src/KSPACE/pair_lj_long_coul_long.cpp | 1 + src/USER-PLUMED/fix_plumed.cpp | 5 +- src/compute_orientorder_atom.cpp | 2 + src/compute_orientorder_atom.h | 8 +- src/lmptype.h | 7 - src/modify.cpp | 14 + src/pair_coul_streitz.h | 1 - src/pair_lj96_cut.cpp | 1 + src/pair_mie_cut.cpp | 1 + src/reader_native.cpp | 10 +- src/set.cpp | 9 +- src/suffix.h | 19 +- src/version.h | 2 +- 322 files changed, 3244 insertions(+), 2678 deletions(-) delete mode 100644 doc/src/Eqs/centro_symmetry.jpg delete mode 100644 doc/src/Eqs/centro_symmetry.tex delete mode 100644 doc/src/Eqs/cna_cutoff1.jpg delete mode 100644 doc/src/Eqs/cna_cutoff1.tex delete mode 100644 doc/src/Eqs/cna_cutoff2.jpg delete mode 100644 doc/src/Eqs/cna_cutoff2.tex delete mode 100644 doc/src/Eqs/cnp_cutoff.jpg delete mode 100644 doc/src/Eqs/cnp_cutoff.tex delete mode 100644 doc/src/Eqs/cnp_cutoff2.jpg delete mode 100644 doc/src/Eqs/cnp_cutoff2.tex delete mode 100644 doc/src/Eqs/cnp_eq.jpg delete mode 100644 doc/src/Eqs/cnp_eq.tex delete mode 100644 doc/src/Eqs/compute_dpd.jpg delete mode 100644 doc/src/Eqs/compute_dpd.tex delete mode 100644 doc/src/Eqs/compute_fep_bar.jpg delete mode 100644 doc/src/Eqs/compute_fep_bar.tex delete mode 100644 doc/src/Eqs/compute_fep_fdti.jpg delete mode 100644 doc/src/Eqs/compute_fep_fdti.tex delete mode 100644 doc/src/Eqs/compute_fep_fep.jpg delete mode 100644 doc/src/Eqs/compute_fep_fep.tex delete mode 100644 doc/src/Eqs/compute_fep_lambda.jpg delete mode 100644 doc/src/Eqs/compute_fep_lambda.tex delete mode 100644 doc/src/Eqs/compute_fep_ti.jpg delete mode 100644 doc/src/Eqs/compute_fep_ti.tex delete mode 100644 doc/src/Eqs/compute_fep_u.jpg delete mode 100644 doc/src/Eqs/compute_fep_u.tex delete mode 100644 doc/src/Eqs/compute_fep_vol.jpg delete mode 100644 doc/src/Eqs/compute_fep_vol.tex delete mode 100644 doc/src/Eqs/compute_gyration.jpg delete mode 100644 doc/src/Eqs/compute_gyration.tex delete mode 100644 doc/src/Eqs/compute_msd_nongauss.jpg delete mode 100644 doc/src/Eqs/compute_msd_nongauss.tex delete mode 100644 doc/src/Eqs/compute_saed1.jpg delete mode 100644 doc/src/Eqs/compute_saed1.tex delete mode 100644 doc/src/Eqs/compute_saed2.jpg delete mode 100644 doc/src/Eqs/compute_saed2.tex delete mode 100644 doc/src/Eqs/compute_saed3.jpg delete mode 100644 doc/src/Eqs/compute_saed3.tex delete mode 100644 doc/src/Eqs/compute_shape_parameters.jpg delete mode 100644 doc/src/Eqs/compute_shape_parameters.tex delete mode 100644 doc/src/Eqs/compute_sna_atom1.jpg delete mode 100644 doc/src/Eqs/compute_sna_atom1.tex delete mode 100644 doc/src/Eqs/compute_sna_atom2.jpg delete mode 100644 doc/src/Eqs/compute_sna_atom2.tex delete mode 100644 doc/src/Eqs/compute_sna_atom3.jpg delete mode 100644 doc/src/Eqs/compute_sna_atom3.tex delete mode 100644 doc/src/Eqs/compute_sna_atom4.jpg delete mode 100644 doc/src/Eqs/compute_sna_atom4.tex delete mode 100644 doc/src/Eqs/compute_sna_atom5.jpg delete mode 100644 doc/src/Eqs/compute_sna_atom5.tex delete mode 100644 doc/src/Eqs/compute_sna_atom6.jpg delete mode 100644 doc/src/Eqs/compute_sna_atom6.tex delete mode 100644 doc/src/Eqs/compute_xrd1.jpg delete mode 100644 doc/src/Eqs/compute_xrd1.tex delete mode 100644 doc/src/Eqs/compute_xrd2.jpg delete mode 100644 doc/src/Eqs/compute_xrd2.tex delete mode 100644 doc/src/Eqs/compute_xrd3.jpg delete mode 100644 doc/src/Eqs/compute_xrd3.tex delete mode 100644 doc/src/Eqs/compute_xrd4.jpg delete mode 100644 doc/src/Eqs/compute_xrd4.tex delete mode 100644 doc/src/Eqs/compute_xrd5.jpg delete mode 100644 doc/src/Eqs/compute_xrd5.tex delete mode 100644 doc/src/Eqs/fix_bond_react.jpg delete mode 100644 doc/src/Eqs/fix_bond_react.tex delete mode 100644 doc/src/Eqs/fix_box_relax1.jpg delete mode 100644 doc/src/Eqs/fix_box_relax1.tex delete mode 100644 doc/src/Eqs/fix_box_relax2.jpg delete mode 100644 doc/src/Eqs/fix_box_relax2.tex delete mode 100644 doc/src/Eqs/fix_controller1.jpg delete mode 100644 doc/src/Eqs/fix_controller1.tex delete mode 100644 doc/src/Eqs/fix_controller2.jpg delete mode 100644 doc/src/Eqs/fix_controller2.tex delete mode 100644 doc/src/Eqs/fix_ehex_eom.jpg delete mode 100644 doc/src/Eqs/fix_ehex_eom.tex delete mode 100644 doc/src/Eqs/fix_ehex_f.jpg delete mode 100644 doc/src/Eqs/fix_ehex_f.tex delete mode 100644 doc/src/Eqs/fix_eos-cv.jpg delete mode 100644 doc/src/Eqs/fix_eos-cv.tex delete mode 100644 doc/src/Eqs/fix_eos_table_rx.jpg delete mode 100644 doc/src/Eqs/fix_eos_table_rx.tex delete mode 100644 doc/src/Eqs/fix_gcmc1.jpg delete mode 100644 doc/src/Eqs/fix_gcmc1.tex delete mode 100644 doc/src/Eqs/fix_gcmc2.jpg delete mode 100644 doc/src/Eqs/fix_gcmc2.tex delete mode 100644 doc/src/Eqs/fix_gcmc3.jpg delete mode 100644 doc/src/Eqs/fix_gcmc3.tex delete mode 100644 doc/src/Eqs/fix_gld1.jpg delete mode 100644 doc/src/Eqs/fix_gld1.tex delete mode 100644 doc/src/Eqs/fix_grem.jpg delete mode 100644 doc/src/Eqs/fix_grem.tex delete mode 100644 doc/src/Eqs/fix_integration_spin_stdecomposition.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_boltzmann.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_boltzmann.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_fluidforce.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_fluidforce.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_gammadefault.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_gammadefault.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_navierstokes.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_navierstokes.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_properties.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_properties.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_stress.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_stress.tex delete mode 100644 doc/src/Eqs/fix_lb_fluid_viscosity.jpg delete mode 100755 doc/src/Eqs/fix_lb_fluid_viscosity.tex delete mode 100644 doc/src/Eqs/fix_mvv_dpd.jpg delete mode 100644 doc/src/Eqs/fix_mvv_dpd.tex delete mode 100644 doc/src/Eqs/fix_nh1.jpg delete mode 100644 doc/src/Eqs/fix_nh1.tex delete mode 100644 doc/src/Eqs/fix_nphug.jpg delete mode 100644 doc/src/Eqs/fix_nphug.tex delete mode 100644 doc/src/Eqs/fix_orient_fcc.jpg delete mode 100644 doc/src/Eqs/fix_orient_fcc.tex delete mode 100644 doc/src/Eqs/fix_pimd.jpg delete mode 100644 doc/src/Eqs/fix_pimd.tex delete mode 100644 doc/src/Eqs/fix_rattle_constraints.jpg delete mode 100644 doc/src/Eqs/fix_rattle_constraints.tex delete mode 100644 doc/src/Eqs/fix_rattle_rij.jpg delete mode 100644 doc/src/Eqs/fix_rattle_rij.tex delete mode 100644 doc/src/Eqs/fix_rhok.jpg delete mode 100644 doc/src/Eqs/fix_rhok.tex delete mode 100644 doc/src/Eqs/fix_rx.jpg delete mode 100644 doc/src/Eqs/fix_rx.tex delete mode 100644 doc/src/Eqs/fix_rx_localTemp.jpg delete mode 100644 doc/src/Eqs/fix_rx_localTemp.tex delete mode 100644 doc/src/Eqs/fix_rx_localTemp2.jpg delete mode 100644 doc/src/Eqs/fix_rx_localTemp2.tex delete mode 100644 doc/src/Eqs/fix_rx_reaction.jpg delete mode 100644 doc/src/Eqs/fix_rx_reaction.tex delete mode 100644 doc/src/Eqs/fix_rx_reactionRate.jpg delete mode 100644 doc/src/Eqs/fix_rx_reactionRate.tex delete mode 100644 doc/src/Eqs/fix_spring_rg.jpg delete mode 100644 doc/src/Eqs/fix_spring_rg.tex delete mode 100644 doc/src/Eqs/fix_ttm.jpg delete mode 100644 doc/src/Eqs/fix_ttm.tex delete mode 100644 doc/src/Eqs/fix_ttm_blast.jpg delete mode 100644 doc/src/Eqs/fix_ttm_blast.tex delete mode 100644 doc/src/Eqs/fix_ttm_blast1.jpg delete mode 100644 doc/src/Eqs/fix_ttm_blast1.tex delete mode 100644 doc/src/Eqs/fix_ttm_ce.jpg delete mode 100644 doc/src/Eqs/fix_ttm_ce.tex delete mode 100644 doc/src/Eqs/fix_ttm_mod.jpg delete mode 100644 doc/src/Eqs/fix_ttm_mod.tex delete mode 100644 doc/src/Eqs/fix_wall_colloid.jpg delete mode 100644 doc/src/Eqs/fix_wall_colloid.tex delete mode 100644 doc/src/Eqs/fix_wall_ees.jpg delete mode 100644 doc/src/Eqs/fix_wall_ees.tex delete mode 100644 doc/src/Eqs/fix_wall_harmonic.jpg delete mode 100644 doc/src/Eqs/fix_wall_harmonic.tex delete mode 100644 doc/src/Eqs/fix_wall_lj1043.jpg delete mode 100644 doc/src/Eqs/fix_wall_lj1043.tex delete mode 100644 doc/src/Eqs/fix_wall_lj93.jpg delete mode 100644 doc/src/Eqs/fix_wall_lj93.tex delete mode 100644 doc/src/Eqs/hexorder.jpg delete mode 100644 doc/src/Eqs/hexorder.tex delete mode 100644 doc/src/Eqs/orientorder.jpg delete mode 100644 doc/src/Eqs/orientorder.tex delete mode 100644 doc/src/Eqs/pair_adp.jpg delete mode 100644 doc/src/Eqs/pair_adp.tex delete mode 100644 doc/src/Eqs/pair_agni.jpg delete mode 100644 doc/src/Eqs/pair_agni.tex delete mode 100644 doc/src/Eqs/pair_airebo.jpg delete mode 100644 doc/src/Eqs/pair_airebo.tex delete mode 100644 doc/src/Eqs/pair_atm.jpg delete mode 100644 doc/src/Eqs/pair_atm.tex delete mode 100644 doc/src/Eqs/pair_beck.jpg delete mode 100644 doc/src/Eqs/pair_beck.tex delete mode 100644 doc/src/Eqs/pair_body_rounded.jpg delete mode 100644 doc/src/Eqs/pair_body_rounded.tex delete mode 100644 doc/src/Eqs/pair_coul_soft.jpg delete mode 100644 doc/src/Eqs/pair_coul_soft.tex delete mode 100644 doc/src/Eqs/pair_lj_soft.jpg delete mode 100644 doc/src/Eqs/pair_lj_soft.tex delete mode 100644 doc/src/Eqs/pair_morse_soft.jpg delete mode 100644 doc/src/Eqs/pair_morse_soft.tex delete mode 100644 doc/src/Eqs/pair_nm.jpg delete mode 100644 doc/src/Eqs/pair_nm.tex delete mode 100644 doc/src/Eqs/pair_srp1.jpg delete mode 100644 doc/src/Eqs/pair_srp1.tex delete mode 100644 doc/src/Eqs/pair_srp2.jpg delete mode 100644 doc/src/Eqs/pair_srp2.tex delete mode 100644 doc/src/Eqs/pair_sw.jpg delete mode 100644 doc/src/Eqs/pair_sw.tex delete mode 100644 doc/src/Eqs/pair_tersoff.jpg delete mode 100644 doc/src/Eqs/pair_tersoff_1.jpg delete mode 100644 doc/src/Eqs/pair_tersoff_1.tex delete mode 100644 doc/src/Eqs/pair_tersoff_2.jpg delete mode 100644 doc/src/Eqs/pair_tersoff_2.tex delete mode 100644 doc/src/Eqs/pair_tersoff_mod.jpg delete mode 100644 doc/src/Eqs/pair_tersoff_mod.tex delete mode 100644 doc/src/Eqs/pair_tersoff_mod_c.jpg delete mode 100644 doc/src/Eqs/pair_tersoff_mod_c.tex delete mode 100644 doc/src/Eqs/pair_tersoff_zbl.jpg delete mode 100644 doc/src/Eqs/pair_tersoff_zbl.tex delete mode 100644 doc/src/Eqs/pair_ufm.jpg delete mode 100644 doc/src/Eqs/pair_ufm.tex delete mode 100644 doc/src/Eqs/pair_vashishta.jpg delete mode 100644 doc/src/Eqs/pair_vashishta.tex delete mode 100644 doc/src/Eqs/pair_yukawa.jpg delete mode 100644 doc/src/Eqs/pair_yukawa.tex delete mode 100644 doc/src/Eqs/pair_yukawa_colloid.jpg delete mode 100644 doc/src/Eqs/pair_yukawa_colloid.tex delete mode 100644 doc/src/Eqs/pair_zbl.jpg delete mode 100644 doc/src/Eqs/pair_zbl.tex delete mode 100644 doc/src/Eqs/pressure.jpg delete mode 100644 doc/src/Eqs/pressure.tex delete mode 100644 doc/src/Eqs/pressure_tensor.jpg delete mode 100644 doc/src/Eqs/pressure_tensor.tex delete mode 100644 doc/src/Eqs/ptm_rmsd.jpg delete mode 100644 doc/src/Eqs/ptm_rmsd.tex rename doc/src/{Eqs => JPG}/fix_integration_spin_stdecomposition.jpg (100%) rename examples/USER/plumed/{log.27Nov18.peptide-plumed.g++.1 => log.4Feb20.peptide-plumed.g++.1} (82%) rename examples/USER/plumed/{log.27Nov18.peptide-plumed.g++.4 => log.4Feb20.peptide-plumed.g++.4} (82%) create mode 100644 src/KOKKOS/compute_orientorder_atom_kokkos.cpp create mode 100644 src/KOKKOS/compute_orientorder_atom_kokkos.h diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index bf5c502d84..e10176f9fd 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -49,8 +49,8 @@ if(PKG_USER-PLUMED) message(STATUS "PLUMED download requested - we will build our own") include(ExternalProject) ExternalProject_Add(plumed_build - URL https://github.com/plumed/plumed2/releases/download/v2.5.3/plumed-src-2.5.3.tgz - URL_MD5 de30d6e7c2dcc0973298e24a6da24286 + URL https://github.com/plumed/plumed2/releases/download/v2.6.0/plumed-src-2.6.0.tgz + URL_MD5 204d2edae58d9b10ba3ad460cad64191 BUILD_IN_SOURCE 1 CONFIGURE_COMMAND /configure --prefix= ${CONFIGURE_REQUEST_PIC} diff --git a/doc/Makefile b/doc/Makefile index 82c099ff70..7fba611361 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -75,8 +75,11 @@ html: $(ANCHORCHECK) @rm -rf html/_sources @rm -rf html/PDF @rm -rf html/USER + @rm -rf html/JPG @cp -r src/PDF html/PDF @cp -r src/USER html/USER + @mkdir -p html/JPG + @cp `grep -A2 '\.\. image::' src/*.rst | grep ':target:' | sed -e 's,.*:target: JPG/,src/JPG/,' | sort | uniq` html/JPG/ @rm -rf html/PDF/.[sg]* @rm -rf html/USER/.[sg]* @rm -rf html/USER/*/.[sg]* diff --git a/doc/lammps.1 b/doc/lammps.1 index 492a600e9d..ee2299f4b5 100644 --- a/doc/lammps.1 +++ b/doc/lammps.1 @@ -1,4 +1,4 @@ -.TH LAMMPS "4 February 2020" "2020-02-04" +.TH LAMMPS "18 February 2020" "2020-02-18" .SH NAME .B LAMMPS \- Molecular Dynamics Simulator. @@ -11,13 +11,18 @@ or mpirun \-np 2 .B lmp - [OPTIONS] ... +\-in [OPTIONS] ... or .B lmp \-r2data file.restart file.data +or + +.B lmp +\-h + .SH DESCRIPTION .B LAMMPS is a classical molecular dynamics code, and an acronym for \fBL\fRarge-scale @@ -249,7 +254,7 @@ the chapter on errors in the manual gives some additional information about error messages, if possible. .SH COPYRIGHT -© 2003--2019 Sandia Corporation +© 2003--2020 Sandia Corporation This package is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License version 2 as diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index d2d47f694c..e1d3b52165 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -880,6 +880,9 @@ USER-PLUMED package Before building LAMMPS with this package, you must first build PLUMED. PLUMED can be built as part of the LAMMPS build or installed separately from LAMMPS using the generic `plumed installation instructions `_. +The USER-PLUMED package has been tested to work with Plumed versions +2.4.x, 2.5.x, and 2.6.x and will error out, when trying to run calculations +with a different version of the Plumed kernel. PLUMED can be linked into MD codes in three different modes: static, @@ -1212,13 +1215,10 @@ USER-QMMM package for a QM/MM simulation. You must also build Quantum ESPRESSO and create a new executable (pwqmmm.x) which links LAMMPS and Quantum ESPRESSO together. These are steps 3 and 4 described in the - lib/qmmm/README file. Unfortunately, the Quantum ESPRESSO developers - have been breaking the interface that the QM/MM code in LAMMPS is using, - so that currently (Summer 2018) using this feature requires either - correcting the library interface feature in recent Quantum ESPRESSO - releases, or using an outdated version of QE. The last version of - Quantum ESPRESSO known to work with this QM/MM interface was version - 5.4.1 from 2016. + lib/qmmm/README file. This requires a compatible Quantum espresso + and LAMMPS version. The current interface and makefiles have + last been verified to work in February 2020 with Quantum Espresso + versions 6.3 to 6.5. **CMake build**\ : diff --git a/doc/src/Build_windows.rst b/doc/src/Build_windows.rst index fd76f3ac80..264e4bf44f 100644 --- a/doc/src/Build_windows.rst +++ b/doc/src/Build_windows.rst @@ -17,9 +17,9 @@ General remarks LAMMPS is developed and tested primarily on Linux machines. The vast majority of HPC clusters and supercomputers today runs on Linux as well. -Thus portability to other platforms is desired, but not always achieved. +While portability to other platforms is desired, it is not always achieved. The LAMMPS developers strongly rely on LAMMPS users giving feedback and -providing assistance in resolving portability issues. This particularly +providing assistance in resolving portability issues. This is particularly true for compiling LAMMPS on Windows, since this platform has significant differences with some low-level functionality. @@ -31,18 +31,20 @@ Running Linux on Windows So before trying to build LAMMPS on Windows, please consider if using the pre-compiled Windows binary packages are sufficient for your needs (as an aside, those packages themselves are build on a Linux machine -using cross-compilers). If it is necessary for your to compile LAMMPS +using cross-compilers). If it is necessary for you to compile LAMMPS on a Windows machine (e.g. because it is your main desktop), please also -consider using a virtual machine software and run a Linux virtual machine, -or - if have a recently updated Windows 10 installation - consider using -the Windows subsystem for Linux, which allows to run a bash shell from -Ubuntu and from there on, you can pretty much use that shell like you -are running on an Ubuntu Linux machine (e.g. installing software via -apt-get). For more details on that, please see :doc:`this tutorial ` +consider using a virtual machine software and compile and run LAMMPS in +a Linux virtual machine, or - if you have a recently updated Windows 10 +installation - consider using the Windows subsystem for Linux. This +optional Windows feature allows you to run the bash shell from Ubuntu +from within Windows and from there on, you can pretty much use that +shell like you are running on an Ubuntu Linux machine (e.g. installing +software via apt-get and more). For more details on that, please +see :doc:`this tutorial ` .. _gnu: -Using GNU GCC ported to Windows +Using a GNU GCC ported to Windows ----------------------------------------- One option for compiling LAMMPS on Windows natively, that has been known @@ -83,13 +85,13 @@ traditional build system, but CMake has also been successfully tested using the mingw32-cmake and mingw64-cmake wrappers that are bundled with the cross-compiler environment on Fedora machines. A CMake preset selecting all packages compatible with this cross-compilation build -is provided. You likely need to disable the GPU package unless you +is provided. You will likely need to disable the GPU package unless you download and install the contents of the pre-compiled `OpenCL ICD loader library `_ into your MinGW64 cross-compiler environment. The cross-compilation currently will only produce non-MPI serial binaries. -Please keep in mind, though, that this only applies to compiling LAMMPS. -Whether the resulting binaries do work correctly is no tested by the +Please keep in mind, though, that this only applies to **compiling** LAMMPS. +Whether the resulting binaries do work correctly is not tested by the LAMMPS developers. We instead rely on the feedback of the users of these pre-compiled LAMMPS packages for Windows. We will try to resolve issues to the best of our abilities if we become aware of them. However diff --git a/doc/src/Eqs/centro_symmetry.jpg b/doc/src/Eqs/centro_symmetry.jpg deleted file mode 100644 index 1e89d11a11bea81ba00ddb2a65d62a3f2e0e2398..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4111 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 Qyr}=6b5W2iQ2+lX08>=9$p8QV diff --git a/doc/src/Eqs/cna_cutoff2.tex b/doc/src/Eqs/cna_cutoff2.tex deleted file mode 100644 index fcec31fd24..0000000000 --- a/doc/src/Eqs/cna_cutoff2.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass[12pt,article]{article} - -\usepackage{indentfirst} -\usepackage{amsmath} - -\begin{document} - -$$ - Rc + Rs > 2*{\rm cutoff} -$$ - -\end{document} diff --git a/doc/src/Eqs/cnp_cutoff.jpg b/doc/src/Eqs/cnp_cutoff.jpg deleted file mode 100644 index fae5c6b636c0f818f8677fd7fce4f402cb03a95d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13431 zcmex=$<%PwSRFvdYWaQ-K{vTlA=3scoIF*r6 zkm3Ik1{nrM24+SOV1NNuHg*Ci-{z52=9a0t*#Vqh4mVZiD+Wr$ zxl3zpT=tzwXIX;Xt0U&|9{#6hv3u4kS98P{&5KgCvbrd03brJma+|NP&=&KGo$eEM z7o{lfoFv82k-Iwic!3aq+vMXDr62JtnQ#i{uH{qIGh4Eji(#p!HH&;;{1&Y4t5k9+ zJyoP7pBW_O6!zFLVJ&B1fLF(7hAFGvuXp~C`nojbZp5r-sq>?%>{+jN6e-VM7VtPr zp@Sp9OF5@feEO0VWj0KEd9&VZyRECZY_@mqLPZTHw1M)f=6gt$P2M&2Y)v!WA@Sy`_$^n(@XZTiR!qvhta2d8_Ry zrO^D0W6l1>o8yle?Y{1@&R_S)Eh(QrmB&TA=5DoErRT`MT~q4R z)3(m~6UgZq)WN_zsa9L;TU24BRk7a6ldOKJ=Gz51(`y&F-S$z*KkZ_Z?HILF@2NhN@0zF0N-%M-3hmU6CI^-Fs{bF;pBJRvD-Yt7luvfG00?l?T-R=-M1=2W98eKr@$ z-1QD8{9KYXd7@F|w+%e=_ zUayL6XYV%6(j3s-Id<;B2&L*?b2;w zmpU1b6fw`@WWVQk{QjMgt(smzQ$Ky~-E`@0>5*->ghIBic%j1gWbzAbi36W`0_!eV zem;3pS9RuxHD?Z$Kh5~?WJjZlChzL1sK!EumPxe_qkV&{zE_7?U(7l5?$!^hvx}S} z!@eFpx?myuzo6FQYKthrG4PF{pC3G-@VuE3sn}qa*6f~ zU%GeFf?LP$ygJ?Y{;F1v{LS@oYre9bynI{OIPcP=!9w2h z$hDJRK~vV8zP0Sa?E9OqWeR#ceHa~TP+iU5-(XoHy_N zXIQmXxAK{K;qkLyXI}|h(5dh8?APJw+I2CvWwxGlZaUZYO~~WM`;ar{GW+h>&J@pV z`Ok26`|GcZVwUV!yJV|cX5r%#KbN%HE~+`cd}{6Uh&g-uxwl2U-4Uf=oNFi@Tr{^& zHblkd)Vz*U6P9LJ+_nil>EU_F@rHW%X|HglPhU^o$=#jZW|cfsf8}D;BTHR9-Cvz* zZ{wQccKuoCyMAM1uTPWJOj1}+PPnY8?yzIS1pntT{~4^K_CL0W|NQbl!@j+XecM%2 z1(zPLbjWGD!=+Fc`ra#OYWMFv@1Odc-2$deWwl$;tFrw4l#ABCw{ZM<9duZ!BcgVi z00)!p-nK1`OZs$|l>OcvveluKU2s!+#FRVnN`1@UUS_IsSr`+-6(TZeYL$S)``|$3 zjY8UnN}JjuQaN*%T`-xVs_ek{f7XkBvh4Tv5=GhAwT`JkKGV|R!_C!}k zM->4Ng~t5tF}dHRlg&MZlTS7MPQ12c(}U=2N9iXb)`H)!pY3`o^*N=nqWw|Ltdg`R zn;)rn?a)>9yz#|Kd28CWooAob)}CHtZlV^tT5$V;+#PUMltKW$VkFQhU1t%v~YU$`h8}p0LR?b*9dzXifVo-W`D+zZM>tcvFFM-KM*F zWp?w=?2cAAJ4b1+?8zP{^`~4Na_*;WbOkCaV*Yg4RVln$_2ZdqM{4lL)yut7olACV zSeE?cV$N`}=dGEnDJ2tnzMo;?`Dv$WFFbWkopH>z`culsOm>+Mp- z;*-fKwHdpUg6GtR`NWBYryfq+x?|;Jl~&yikEB_>GkKM3JRXH?2>q?OTHX6m^x^5Z zm(Er+=Z<-Ke?^1RGArGzTt@EX!xw@=Pvkm!a@~Aqe&^=8=^o#{nq0c@`IFp}sJ=s7 zcOv|D%2ui59gb3>@w?<*Hv`67?!+f{-Drg z#$l@M6|`wKi^p~QOzGVlZ+f(MM$Bq!nfE94T&e%A1^(A`7w(;JU-Kv1VPDk7s+9!!~bxw?g7=M%DZD536;xj8(Sz?mFmFVaa>$(5qN( zBL#EWJdKP#7Q4%xkIMK{nz!`*x?%dCVc|~sTgTFWuU-CAYICHb=k{AS+x6a>z586V z(`QCo(CgWO$`evK+!Gw6Jl?QgjXzZFa0iOgQY?l zsD9#OkY9fif7Q0o+&g)nwu@|e{!=;8WkSow{7ZEYcPx4R(bWINGTZX{#Sz|T(<4Pv zEc+dTA~QQ!d7EW72~ApYG)m4nWqzmWicPI%r=+7-mwI}z9&J3C!f(8Q?fe~vHK%Xs zKAXAu;i}RrW_Gh9{jMyqS*kMs1Ix9A0XrWuv+bW$!n(=-KSO5dtZLz=`Dr#T8Um#T z-~Th*j$iE`b8q`<-rm$5w~}I|_ufssJv%Kips!u*Q%Jk)BS%e7hj0ORRhH$+(_YP- zetKf+x3!y!SN-^4Tf@Cew{|SlWO&gQ;t({Y_VE34+kP#I-h6MyN^tpYQkbjj}{6{lwFv72{=-c$QAy6qCrs zVY6=o1MA;}RX5k3KQcMLUyZrfQt;ZOZDQAUXl`Qk^xJE?HY~E)q3rZq^DCuZGH&iU zTVoVg%scHJ(JSu)?twnyJz;zxb!?WwC>4cOKrjvpaJAUAO6S zXQU@gi|Wmr@bl5XD<*5(N6!ydE?@`J$jd}PQTT?!swZD_fOGPH;wLXmA{=kMYH|V{7x=!mwv;O z>LNchSI?E$q1w0ltC7vj^L|C4zjVst zqXM{2DSX%B;PlUD%)B9&`6oMlsbmY1}F> zWvRk^1%^+eUgs8`u3vFu$<2>XPab<d2yXd25dr1jbH8<$xQPpego}&W zY~8^b)%DdiOE9` z&Y;`Zh1N2ancv@eMboSAn9hffck-_H-`?XtFsoW6z5#)%FV7k$0^-_J;B29*$2Thq`7)cd+Ja^a{0BE}3}aMQ`8Lmuz?Q8}nSZ z@km@;sHm#hciGc9LG}$x<67DIU#~yXop$Z5)1~ejm)p&8937G#>1|sNx9#|Nec9F+ zF&lr$ji-#>ib|C0k~1UB!FA z$ZNLH;)NHQ+&X0%FJ4u?x#r_DQ#0FD+(t7K+%liIJB78mPtFXG=J=zm<%tKIr~0I8p1c%!#PCvHK$3=Ba9plRr(eI@1+!@P zYwDBstyrtHXtT6&q?~fa@p}Q@;THUdBb5`_rGq&CGf17YoshTgP8EAnyQZq}npaiV zbr+RIN9(OrRDb{Q@ZZvPK?^>uUh|???QT-vnca7m%%5!bsv~palem(;hg<%zm&&SC zPExKa?7#WZ<@#-p*Q-qVm+5pgYsTBP-E#JMn~wfxIQaIXRM+*~>a`10>KoSm z!Zvd7;KZ71Z`zLQoh*E1^W!0#bQx4+J0%1Cq(&AstaonG~B<}J)`*d z){U1|R33NVl|TDF?|ZFdQoCZfGc#=7Om7!aKdGRaz<6ig;WLw;WrZ)l!6x6}G?klw zlW}HJaO3q0x4Yv_85ej)b$(iH3+goYrsme#ew(-r_nn%mn()Ex&!l-ry#n7%S?Ydi$FA`9IrcJzGdCSQ^u2Jx&hMSSuAf?J z`8$jGA}52Q<`*ybb+2xN$HUNx@JTA}G0T+}ew(VeL^aPujO)TwQI-|`2Ap17YAfb9 zu8#t{0VnZe!s#OA9fuc8yW{B85a@YP%Jz8S&#>T2uVeR}zrJqi;cYH?#`fkn#ey2| zdTCDIsxj|X;E%bpu4SS-17g9{9}ge3%6a-VT8B^geKvTP{q*%lhZe>zJGpJuLq+Y{ z9A}#fgYDvr}U0n6z}Q zyQ4z6%6!L&W9&1My1zA^pXcY9sdK(HElqg8wtKtk5l%&q+~`YJxI0)>Cco#pl|4=O zkjTnQ58Z3^_VX<8@N!h#s!_zLetO!LiuVbcD!m%{t9Gpa9$}^}^ZM-B2WK>N^qk+x zuWD)X&ktVs^mWLZdg-%y(<;7u9}oCcZS!)$$+Ejby4w%6pP9-g6x+3R9z%=JQrRh! zzlUt$@%t-PQpsOxt~=wh-_q>9FWCvX5BN@r1oCQe+PQa4DybHzzPf43QtfH7heS>q zJ$A3vu9I%u$@`+!Y!Or2!7mC;{1d;dLm$a&KeZ{^&6u?~@4dxk-c4`XLvCvoY&-4w zp> zb=T+s>89y-6HmNVU81p4XW`P1*LDh@)VL@m(=Wg}Y3fropNtdSlNFZ*`85_MD$GB( z^IzH4`eOzApI`pZP+RRbo6qZ%vUlI7hMT-QL>&ICzBgs5)AQ-yHpZy^oV2H5OVk5f zodtjEd08FpXG;BfeVTcTzU<+JF7y5~beou@#H6fgh?}&(_BrP#>Bztzj0>z8V=cCM zC!R{MwU^s0%y#)x#Zum3tU}t8Tki z=W}ZRzE56XU(I;MzG?M))ou6mZC$tDekaDZPNHDD#p8FDnu;6sXK;G=$iHl7yq(v0-smR%;HzB7citJ$cxOj!? zk?;4D9IyXcZSjIDCM!NLXKzq&$af2-i`{2(`FTmYSIpR}^81`{ z5wn)2kfp*;7+5BU?5+=4!+%Hl*pAyp+#;3T9IaMwb7L|th4}B9u(j^c)UQDg9PJ#0 zZ>_z)dWpA7*pf3rO|nytgs}8ZdVFr_lCmE~5%&+|{0h%a`T4|r!Pmpf{MBBURvPD( z%L}%vuGla^_x+TH3zw{gN<6fFzm8ZH=AFAIuBtnK`yCzL7=wp-g~#s{1vw|h8wgF8 zu)oa5yzRKiB+r|VS54#C{zmTNPd@&n(x;CW%O$;dBs=5KbV)r{lNdah zcLu63u$@$4ymKXXv*uRc{d$KME6H9p{1-H1(#+uO!nq&y6y}#E2r)kL^i)pB$;$&* zc~htT_TJVh!IZOx&s=9#NlazCFK=m`{P*IAwOTe3g@@%>!lHj#$8oD_ zFl@V@Un1{#qwIHUjr-2qDgIR~)h+JJ49wn?*i5y!KmDzWY`@|2kD}MTf)*CN&_CC9 zD*1-a_T>W4{%9{gxYuzBb#_xDe>T1TmU;OZv1^AD}rvf|97n`WA){u${zr$@+D|^?!&Fge>*7WiKcEoxiDLliuX@`bW3zRy-Lr;Y8(?ZRtL9s5SMjqG^=yIkKgmYS>2ZthI`Fn5>g z)3Q96Q)VnGu?LN zR499X=5KQRUXOEYcGP5Cd>;2^+U?#0D+TtI&gyvcCVO(XR=};`4IZ-R4#-st%vIZ& zu=Y+$)W@D#H>bv_FFf7*>NQ`o|Jv(8(GGeQDJ@Lm%Pu~dvd!U>+WP4oMe5EUlPO}kT`T*x*XHL9U+=CA_rI{`wNlB>3A?7~<~ZDTf41}aq*4jq7b3q8 z^lE&&*Rki8&UOvsU?soU>Ydvd*=&|AT)KIG?3P2K8~?tVy=MP{^CnLpuY8$%MW^SM zr=k{n{ELn5zYoe!T&cHhsejbQ8NKC|e>PnTFn=aJrG5Ip!`}AO52x)Z`gHd8nu@Qp zOgtvOyLLNdb$599g_t61KV6=++XOdE+FJHxDJx3@yYTs~#f!yRHeRh;=04f-PlMB|Y478|afj;# zZ>{QeWQ?+Lv{sO1V!WDtb^2G&XR}|sdtBNcFjac$X-6-Hxwq%ZzgMVB zTL07Z+r^$6srU0Y&uYwV>lboqH$TdGLvHT*BDVG--*Dr3i;`!2U3Bl$CTSi|@wT70 zWp|u&7Q8lTLQSZqm$U;HyYsGX44-dwzcf9~n)g`gdQZx=Gpjz@^2OwbM-)rd=Ixqv zi?R5yih{sivwoGOo7g9s3clHJ$}p}&U2fN|j`hjH?+n#fUTu(ita`n2b=3vkwc6|_ zmNY-fzI=0<@Q&r1kFJZoIeqa|bG=uOv;C&E%_%)T@%Duusp|2p7J{n*@mknU(dd-+Hm7qbni0Ni@Wb$lij&3O_bwBVZN$I z;XM_hDN|SrS&9O@$}IC%&aBxf7N3!0_8 z`yJaquk%6OiYZHr&opx-PnmWj$Q~ zo|~V-`)GOi)#!M!$ERKFqHRq46V|?te!Dk+t4osDp2DfgZ=&9mm&`UXm+V*aDPOEQ z;Zg9JwR(jgWg;DJHAJ#cR4KAq2kwwfjeQk*?`7h_yzSYl>ryX0l%2a#N?OkNl&Yh( zbA8Mbp>=k9N^foM+j4gIm*>mhe3d&~wclD#_@mG5)KgybeUEOR>ztLbrEJ<xckQZck9Z@+R$KE-9kJ+MXIAg}f zjd~VRspp)x+bO6fZ+tST^r)x$YnwxcXC9euGjnJ0&bnQY^-xyjwcj?s#ve=GG|dkT zv+CIU=*QJhPAYL9Z@Zp-cJUyePs{C7Ugdk47I;XjZ>^2^xTfgH<8?RQh^>yg%c!R% zV|G)U`Gn8}Gp(@2>#kLlTYl@@RO2sp(J)x)V_18~GTDSrKl=FBZ$IvSX-W2>hkUY! zgf}cdk`xm@`RKLy99?dCrpY(@k1f*O5ht57=gR9m^~6@)Mc(YE_Oa;E_j)F8?@MpK6Lvar*;Fm=yeSHms;Zt=@&)U6%bE5?%qhJs+jKQM zdV%Uu=eFCb36)GiY)9*2HqNPfs$29Y3a(z8~^0JYDtWs^^}| z{+qVNfXG%#Kxkqv)ZYY#Eod$I9|smbT3oiq3J)QRQb`@IdN9gzV1B zD{D28dqw1r8h|TloWu?zZPVR~8&7YFeLPd_XYaHnMlwM*F7hUmCh_%8e1E6x)0%hu zn~%FC`X=SXh)L%kFVx$ze~MkjO7(;n>*JEPT0wehIE|mO>OVt3(GH0;eWjna+fzhV z>KyGjaeLDfosXGq$5&lj#PFkX-hu1)xTO{Q`%U(&DpHM8SsSFXbV(miWEBQZVJrqt`m7Qs(la-{VSo&2Cw))VwuqOWzZ| zf2EvXPAmUbKl7iVYRi8HTmNN|@;B|$e_vhx^Hr_UiGL?Q+uvJje?Iu-H1}`*Gyi?f z{8u&KXOsP=n)BaR`+vUjD|O=E$saQ$$JwD2(W7f22+NF@C8Tk(U#@|DO`Oit6 z_{`HR<2&tfZrN!$>C-U>TBf)3ODy;BR8?Txx2?Zkaqa9%Uv# zUufQj1E?+iNzl zy5jgY|6b##hI8tpc`UpHmfZ=sFL-3hi-xt|R-Y|+BCHzy#+>s*?z@r$nHDjyzhBjSQ_nf$yrDJk8Mj%-JgzL-vdA*^g`UxclF3WgYUS@|zMtsj zzGp#o?DHeNc03)%63!o&m@J!@nVcCVVzOl72Zf1|>6?!pb6t}XtFv?8D#U&>Cq zog%-gA?V?cNjGj@IvV+&` z=Uw_V?LJ<3`#SWs(y;=YcAak98=DfuZf`k~qv%n4)S^ZCD2vd#?08uwlSv$xc6Xl6 z-EX}0&a*qu;)1I>auXKaXq#~Bx`n8wE1xWjnY)Op`suSSb0^0hbjw#ZOnW`y!F==6 z6I#u!p8Y-9-fVa%Bv{HyTGi9P^T4F~Y?l?2kMKHelzI7n(Y$LBrZ3rBayDJoI;sC_ z=`oMWrSflu7EJt}w+%8n7c^yQ>fcoDo$0n#$CaZmS~>2vu80b8a?U-HF=fSS_okZk zh?@-aZZXWeYR$f)Z1UxwH(O6mS3K6J=VN|5=f}}}W7WVNTO8!n&4rk(c|S=ryy5t> zdBt|0q}x`dmwBfN@(HQ$h@KGAa53m${*ea)@vNG1QeJJ>=B{AkoVVqv*2Ec>-FI>y z@qA{8nc)@B_bK^^?z}4Irh|_+Sn^kI>g!vxWvQlD`01kuE}i!Dy2EKBw6u`r7gI@z z-CwD*g>$Oywtcl%I-MH*ajM&XLpH0&+e>TK86{UVPYCQ^&dImpwdW_%Y(HIP~eaS=`;Lr?r-9itTP%`-!LHbi$97x!d_BZ4g~+ zHSY=U_iM*G=dZWq-zdA`N&DD?(gT7ED>5eq}`i`$~oIrJ7z#zcl~VJ6dvL z%3Q7AmD5e+Uz<$*!K3{-vCY>zCF1WsZy`0eV>#y9v%Um>dUoknj5Wij0<*2W>Q&$U zzOd&T27IeNs4r`Kc;@l-0)<~~4pzon+`b!G_@6=W>+YkO!JZfVZJAHTId52NwrabD zu*|Dxw#6>#qFlCZuMV$ge7EqpO7xYM$sYqU583a?x*Ga!k^AY?N1Ku!8s!$|^G#XG ze}{XXaK`;T^VT4cmQW-CU>Ri#=11-`?y#qfWR_#b>5T3+kIktF-0*ln(D$=@6adt#g9USoGq74~z0E~+6BTy3_!cSFJrbz#yJgeq$--#bm0Z64eZgm)RW51yuQr(HROzU^ zopDawyI+?p?E8tfwvG!Q{+#>me(P7ljJ?*aou~Hg)GYh{@I_ zvv#4XU-jYXO6;=gfp_B@C*FzN@c7-?sk-LYXX2-5@yCUF^IaluFm$OB6EuVD0<+9-Io8G<(D_u38EY*4IGFAHlgIH8Z z?Wf#B!n*73r&Yb!s_o^RzwJKbdZRG6{|s84KYy$JXSk5L|A=z^yd^s2(p#?IaXlP)u?x8VQuVX1SizR7b@k$Kvl3NIa+ z7eC`zQ+|8qb?I-}CjweC_4e~}OMRBt%=yo-hwFynwh8B~b5oam%-zwes{DY7fob<^ z;}_xo%wLuNXOKSmpW&lYSa;!UzPp?^uX7eYJepEe`uz^?w#JWIwhe!>jb7a=ZSgvq zXew=ZJU*&OTDevC&dop$*GpQ{*0NTrYHF!pVDg_Dn~?S+_E2)bg47#-cKT~~`)n>s z&5qi~=@EAFk5=90-}ylj^RIKpT4hO1x-1qNBWM^qS@Fm|sX~q~itGvh88S3#qvpQ~ zefXMtN)S-#P_Mqs)UlA|UZ^cReDKr21 zlE&;;&m-8k@BHwKZKWsk(f;y|*DilUnHKK953N(c4%N{pBGr}UOTnXzx$v;36nGV{)Ax$evU#`&U8-NAmvw97pUuU%tT z%}mhmYEUWiRF1x|2QpE#Vz18eylcD9W!LU^_cmTX{d-)xpK8kCOpY|O6Y9~^5dgt)8bYBH)!np(-=G4WVlUR;jA zy1v`XqNl4ac(mwr&bHSszcf{t_#ZL;Xs8b9)%1F>_g2z9WhI;K>04U#XBa%+FB*MO z_R6VC9`B#{?Y|l*@Azi_&v(B68LnKH|Ie_u{HEazu}bbbmG0fEqbvlC-fIOp-21Ki zT!iuMGqzW8Sl5th?c}#P@-%kQt&3&6p0oE)tXbGDnU~h~pCRDUC4ujG{~1w`8CHtGVPq!>#*IqpoTFN_i}{QiD~qOjw)YXF~vQ=^gnp z6ZQBs>CZ7vWi#H0u7aavrr)i*h{@3H=QZE?uI_1hlrn4_}g*0hBaZ(MP5JJ)(mQT+phP~F3Dt}yj$ zWw(!4eZCa4bIa0YDrcuAOmVmnIqBX_|341`f1g}^Jou|soMs>I#G-v0UN5LJ70`-Q zf2WYxopbob=l{;1h}TIH(pR;J@4xIgcEDF zKlRSLYRkWu^TL&FB2&%2luq0*T{?ivQF+G`w&R6CTb61@uy5Zs=S7fWrB>=IWzO(L zo?6!SJv6Q>p59*T1}XDb z9qCC5ww&{3+1bKgvDic00#6r(xZ1U{iM^T~RPu<+|MfJEo9v#Su2-|L#r6wsi<|al zyO8bkxtv^)_h)i4@Sh0Z3u=@ubtn}(sIPhGT^WaX>&+);aukJw4pbky)M%aS!rH{> z>1m}f>s;-Mg{StEJiFQwJtt((ruRi{v!h=)@EJVTTX;P6Mctu*mepBO%roQ`ZHqcz zyJRibz7lDZ?F((DfA&7VQ2ETtg^wD4yk**L#a-h2e9?^5qw1-rbwYO3Z<{u$^*_Uw z$>CW+Q8mTM1_{rU{?&6M3Ppsoi z+HYCC3AH`2pni{_Kpo@xee1U@)eQapwvBtI>1MssaMQC}41Viul)QZK%H9Lov+KN- zn>>DG*ENU8O>zo7y=LdXT+Jf~r>eMYUv_4HSxDI|_g$Y~{@8hEakNaW|Agx+y@EF6 zXSdY6Eqs}#H2HnZXN~h~`0Y6-IJcia!CwB8@6q;IXx-+%lkd7VC4XMG_V)6aJ6$IW z1sBtY-VJ&r=Q?E!r*SoLM@3LUbXQG?%B8!rvod=5Knoua)q9y}WqZVspN| zr?yxBXV|h$WYcTC`clWN>vyy>mTG#1m=&kws~&n^@%n&B%-i=ztiODe4l4g=I`y}> z`!4;(g8AW7Ch8S;rfzUAF%;b5k}Lm(EBw*sk88J0S*kU0!kr>-^PormQ+59{EcD*0 zx%7B%ZphTmdwPG|MH<3dDry_A%eEFNe7qYhvMuJ5e5UvGK*d9|nPqx=x2HL8N?vER zPXEW#OOFCJhy+Y6P^gl(O)F^18m|`@PXFDY>$5~$F=3jxs#VRU&dIh%7W8*! zu=c(bq}{;%Fddi&ngKmDucl;?j2rwQvDtbNiowA0H+_S7T?~C1X@NzqMuHo%7PuN8FqD`;=ZWcYJXDRyd!x8RkuG*)+ zUhpe^476gXn#3BkcmBrNbC=8Pcq*w<&#ZP@UF&UO#?ND3yN#tEFS~u=;wRP6r65Z{ zoosME0TTr&W!Y)YNwbsp9LbB_SFDxhtoL-svtD%K$<%PwSRFvdYWaQ-K{vTlA=3sDP_{PX6 z$ngINgA4;B0~0gI4h9%tV`pM!Wntv_e}utMfPs;PiIJI^iIs(k8KeNDnuS%6ja^7l zSjkW%ki*C^C{a{7sZh+x*m>grTMQhGj0_C+41cF};0GHvnuNYSnN;59D$ITF@rP@T zn?l0&2mRn}KXdBOdU5Rq^(hA@eV4fVt!y9vhmdB@=||HI-<(J+D)|(0&m*^M^0tVR z@(PwqdRyPRxCGw$Zt+M$W=X}K^NPnW?pC}~;H#f~uXL|T-9DQi(HrjU?@lXXm+g5X zaXY-()_-Yg+poLxcW;>Y?*8+r*ds2kACH(WJ*U86=J{9Lo_F5CXFZ2`XC6=KVc!^_H>&M2V6A9CjZrs%@Uc{%DTrIu7fF*~WZK{4?Tz=hCKi`Ae z*EXvJ#-8_PU1svaTjJQg38wc8?@P=6yCt$xRQ=4Riaq_0*7saInWA}h%a)4w3VGhD^Sh4(Y!irjwbAoG!^TVH znFnWQyp_G5nwk2OC**VJhf>Y66HfUvulXftxmM8WI@_;FmPgo{9x*Vd%zcr$PB~xX zeDITs$rBgJTr)dzbxC%&XU>KbFP7xp^7fl^_=(WgPZ>YWbE{>tjv1U3EMFV+TTXcs z-xiiNH#>Ue%af1KKmEa7Yq`zBxHBb|vD!9KU;21@;&p#z-l<^}ZJR9JY0s;=-hM-k zW>HtEGxz-S2`>W=cy_X+tUg^OGdb>sPH6Ual@#NX>bFX2WHWxKI#xZ6zx1lzTlI0^ zHn~8(5~K7()-ivaBYd}=TtDOZw=et+k4zV>^OU>sxTL=zJBqW=enG&uQt954WqUS0 z$=J_oCzrGSYyawub=TZ=3U@B~!*5i#{2)tqR=C^M>MIL&2Zf!DJCZw1Q~JXB%I;s6a z2R`kRI5RDrcji{sh_}~DY$w=7w&;GfUczVhdF=+93cJ!pyKbJ#6jPpG_)ayQdy=}% z&&R84m&q^Z>tgqLHu3%|=39sC)wcgyG0%Q>k>;+)^AGNCfBIylvtZzbP12^`{VR2D z&pde9grS;&LFlc?B(?*=HUAkjm-n2z@c8QMvlGt7cYZ$X$8;f@o7?%>#B&OU4LcXt ztL$LlpPRY#^upP?6At?JY!|DV>UQVf9F>lJXZVU|-BheBNS+mQ>3(5m=Jf(;mdk%F z&pc6ivER5aPk7dz+dE}Guk}k=^2}maWphj8=XUEY442<3-+r9zRsEwpC#=f%u&(cM z)rD!>r5Cc8tLLy@K9-QEX72Xg!eD~z^0xWP$<Q6j4QR+ zmU<-xzTUfe_od=n_vf0ft9&xV!9|1)s!^x6|UwRr2sKZ#$p{@N|?N;pxg z^gi$Kfs5+z7cH{9cjmZ9RccG_@sz?JH$Q|~>b$96EwSpv@qgh=Wju?_t)H+pJN1pWTDE zS9j{Bzp0<&m%a5*zSs8WbF2mVwO;JLT6T&ka25ovbcl!BxA6AyUjB5Nu|Q8WVTL!?OCikE7xm7Rr3{-EVmnvX0G`uxM$CV(na-C zw=b`}zw~u`*qW!3U*=vn40#zOC3Hi#@qx#+H|65r`OA-IyPcci@%zljIn}e$KUwO0 zi`P70e8XDk@yG8QXC6CR^wjazhvzQrGw%GIcFeiE;l`hX{=eKT6<%)R{}=P<&BHaa zx#v3Ez6*J>zLk^ubnnu`-@B&=Px|B|FVm!1Y{~Ij@=j!&0{62G5C1bnEY8rMc>mD_ zufE$GPyfu#)VzG?`r{jwHzIX=&iHOjOOu~>YOQK7OWmg3$^S0Ox88hU<1c&Y$7_Qb zC*S!prK?+8=1yCg1ci+NRxHduEiP#%>DJ3wy5Mo$cbYzrZW~_C^X1uAy(s-%g?|4n+j}3s zM;n`}Ki=ONQ8_R4-#ljZqvtfYt5|g{o$;n>;Uw#az11<*F&?aEm7laOOBPH2$R0iG z@_ufM>vE4LU)w#|sO{>c%v8QFE$z479oxL~h^)!9=I03oyCP5g_*2XNj4kGxo!y1_X;8>=4gJ*wFG zQJnwzrby|3bHY~&CM0&8x!L1mv?X)BuIz!@#>hnnFS@*(ZM-;fV#C(;y0T~4qZ$4+ Qyr}=6b5W2iQ2+lX08>=9$p8QV diff --git a/doc/src/Eqs/cnp_cutoff2.tex b/doc/src/Eqs/cnp_cutoff2.tex deleted file mode 100644 index fcec31fd24..0000000000 --- a/doc/src/Eqs/cnp_cutoff2.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass[12pt,article]{article} - -\usepackage{indentfirst} -\usepackage{amsmath} - -\begin{document} - -$$ - Rc + Rs > 2*{\rm cutoff} -$$ - -\end{document} diff --git a/doc/src/Eqs/cnp_eq.jpg b/doc/src/Eqs/cnp_eq.jpg deleted file mode 100644 index d4213144424331690936b0fd96014ba8ea8eaca0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 23959 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 TuTRbW_1poph7hgB`hODucj-gp diff --git a/doc/src/Eqs/cnp_eq.tex b/doc/src/Eqs/cnp_eq.tex deleted file mode 100644 index e5f157e6ba..0000000000 --- a/doc/src/Eqs/cnp_eq.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - Q_{i} = \frac{1}{n_i}\sum_{j = 1}^{n_i} | \sum_{k = 1}^{n_{ij}} \vec{R}_{ik} + \vec{R}_{jk} |^2 -$$ - -\end{document} diff --git a/doc/src/Eqs/compute_dpd.jpg b/doc/src/Eqs/compute_dpd.jpg deleted file mode 100644 index 549f259c6cbbb89c8c6a8218b5b43af2a688ce3d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21381 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 J7SI3R1OQR31p)v7 diff --git a/doc/src/Eqs/compute_dpd.tex b/doc/src/Eqs/compute_dpd.tex deleted file mode 100644 index e46b0b4dd6..0000000000 --- a/doc/src/Eqs/compute_dpd.tex +++ /dev/null @@ -1,13 +0,0 @@ -\documentstyle[12pt]{article} -\pagestyle{empty} -\begin{document} - -\begin{eqnarray*} - U^{cond} = \displaystyle\sum_{i=1}^{N} u_{i}^{cond} \\ - U^{mech} = \displaystyle\sum_{i=1}^{N} u_{i}^{mech} \\ - U^{chem} = \displaystyle\sum_{i=1}^{N} u_{i}^{chem} \\ - U = \displaystyle\sum_{i=1}^{N} (u_{i}^{cond} + u_{i}^{mech} + u_{i}^{chem}) \\ - \theta_{avg} = (\frac{1}{N}\displaystyle\sum_{i=1}^{N} \frac{1}{\theta_{i}})^{-1} \\ -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/compute_fep_bar.jpg b/doc/src/Eqs/compute_fep_bar.jpg deleted file mode 100644 index 772ec9c0450a35c52b5b927cbf20e7d77e373c93..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18106 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 A;Q#;t diff --git a/doc/src/Eqs/compute_fep_bar.tex b/doc/src/Eqs/compute_fep_bar.tex deleted file mode 100644 index a40aa1c297..0000000000 --- a/doc/src/Eqs/compute_fep_bar.tex +++ /dev/null @@ -1,7 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ \left< \frac{1}{1 + \exp\left[\left(U_1 - U_0 - \Delta_0^1A \right) /kT \right]} \right>_0 = \left< \frac{1}{1 + \exp\left[\left(U_0 - U_1 + \Delta_0^1A \right) /kT \right]} \right>_1 \] - -\end{document} diff --git a/doc/src/Eqs/compute_fep_fdti.jpg b/doc/src/Eqs/compute_fep_fdti.jpg deleted file mode 100644 index ae8de241cc132dfbe0d932baf99a9e066ab178e1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15544 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 Mx)?Nw#Q$#s0RPi0IsgCw diff --git a/doc/src/Eqs/compute_fep_fdti.tex b/doc/src/Eqs/compute_fep_fdti.tex deleted file mode 100644 index fdea6faa3d..0000000000 --- a/doc/src/Eqs/compute_fep_fdti.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ \Delta_0^1 A = \int_{\lambda=0}^{\lambda=1} \left( \frac{\partial - A(\lambda)}{\partial\lambda} \right)_\lambda \mathrm{d}\lambda -\approx \sum_{i=0}^{n-1} w_i \frac{A(\lambda_{i} + \delta) - - A(\lambda_i)}{\delta} \] - -\end{document} diff --git a/doc/src/Eqs/compute_fep_fep.jpg b/doc/src/Eqs/compute_fep_fep.jpg deleted file mode 100644 index d84a76b0ddfcca48421c272f9f7fe64a6ece5cd6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18055 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
RV5KF^a>KW}~);Q0PO!^2tsbpA73{P`#PKf}TD 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 J1^oYS0s!>$BGCW< diff --git a/doc/src/Eqs/compute_fep_fep.tex b/doc/src/Eqs/compute_fep_fep.tex deleted file mode 100644 index 718aad3c40..0000000000 --- a/doc/src/Eqs/compute_fep_fep.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ \Delta_0^1 A = \sum_{i=0}^{n-1} \Delta_{\lambda_i}^{\lambda_{i+1}} A = -- kT \sum_{i=0}^{n-1} \ln \left< \exp \left( - \frac{U(\lambda_{i+1}) - - U(\lambda_i)}{kT} \right) \right>_{\lambda_i} \] - -\end{document} diff --git a/doc/src/Eqs/compute_fep_lambda.jpg b/doc/src/Eqs/compute_fep_lambda.jpg deleted file mode 100644 index 5ef9e8b9f2fbce24c23d751f23986e87f2a16445..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10511 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 I4d(wh0i*$1IsgCw diff --git a/doc/src/Eqs/compute_fep_ti.tex b/doc/src/Eqs/compute_fep_ti.tex deleted file mode 100644 index 6222dbd503..0000000000 --- a/doc/src/Eqs/compute_fep_ti.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ \Delta_0^1 A = \int_{\lambda=0}^{\lambda=1} \left< \frac{\partial - U(\lambda)}{\partial\lambda} \right>_\lambda \mathrm{d}\lambda -\approx \sum_{i=0}^{n-1} w_i \left< \frac{U(\lambda_{i} + \delta) - - U(\lambda_i)}{\delta} \right>_{\lambda_i} \] - -\end{document} diff --git a/doc/src/Eqs/compute_fep_u.jpg b/doc/src/Eqs/compute_fep_u.jpg deleted file mode 100644 index 62df5dd0c03a6d20cca157cbc46053adb77ae90a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9337 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 diff --git a/doc/src/Eqs/compute_fep_u.tex b/doc/src/Eqs/compute_fep_u.tex deleted file mode 100644 index e847a9ac44..0000000000 --- a/doc/src/Eqs/compute_fep_u.tex +++ /dev/null @@ -1,7 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ U(\lambda) = U_{\mathrm{bg}} + U_1(\lambda) + U_0(\lambda) \] - -\end{document} diff --git a/doc/src/Eqs/compute_fep_vol.jpg b/doc/src/Eqs/compute_fep_vol.jpg deleted file mode 100644 index a66facad39308af7e4193c82b3012ead5f51a225..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15209 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 JG+h7xCIF}CWMKdR diff --git a/doc/src/Eqs/compute_fep_vol.tex b/doc/src/Eqs/compute_fep_vol.tex deleted file mode 100644 index 0301e39788..0000000000 --- a/doc/src/Eqs/compute_fep_vol.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ \Delta_0^1 A = - kT \sum_{i=0}^{n-1} \ln \frac{\left< V \exp \left( - - \frac{U(\lambda_{i+1}) - U(\lambda_i)}{kT} \right) -\right>_{\lambda_i}}{\left< V \right>_{\lambda_i}} \] - -\end{document} diff --git a/doc/src/Eqs/compute_gyration.jpg b/doc/src/Eqs/compute_gyration.jpg deleted file mode 100644 index 228544443459e2c13b9ba1e860d8abd5e02f9ffb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3658 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 mO/(5<(r(t)-r(0))^2>^2) - 1 -$$ - -\end{document} diff --git a/doc/src/Eqs/compute_saed1.jpg b/doc/src/Eqs/compute_saed1.jpg deleted file mode 100644 index 6bad3a6104904ff97ac5982d63f88cf68bb8b50f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1471 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 XG^Ozd1B29hNInE-MskU%|8D{S85C)u diff --git a/doc/src/Eqs/compute_saed3.tex b/doc/src/Eqs/compute_saed3.tex deleted file mode 100644 index 5988a620c7..0000000000 --- a/doc/src/Eqs/compute_saed3.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - f_j\left ( \frac{sin(\theta)}{\lambda} \right )=\sum_{i}^{5} -a_i exp\left ( -b_i \frac{sin^{2}(\theta)}{\lambda^{2}} \right ) -$$ -\end{document} - diff --git a/doc/src/Eqs/compute_shape_parameters.jpg b/doc/src/Eqs/compute_shape_parameters.jpg deleted file mode 100644 index 9e2374561b40690173497a2e1c9a28c869b0c819..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7007 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 rt@pmkOd$@waOXj3ANA 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�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 diff --git a/doc/src/Eqs/compute_sna_atom2.tex b/doc/src/Eqs/compute_sna_atom2.tex deleted file mode 100644 index 98d8f2efa6..0000000000 --- a/doc/src/Eqs/compute_sna_atom2.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentclass[24pt]{article} - -\pagestyle{empty} - -\begin{document} - -\begin{eqnarray*} -u^j_{m,m'} = U^j_{m,m'}(0,0,0) + \sum_{r_{ii'} < R_{ii'}}{f_c(r_{ii'}) w_{i'} U^j_{m,m'}(\theta_0,\theta,\phi)} -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/compute_sna_atom3.jpg b/doc/src/Eqs/compute_sna_atom3.jpg deleted file mode 100644 index 41d6774e9c8ec8309c3be5ce151a8095a633098c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19644 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 ZsXBT3-KW_7=CAJi!VakzX*B=;n*iZS#}xno diff --git a/doc/src/Eqs/compute_sna_atom3.tex b/doc/src/Eqs/compute_sna_atom3.tex deleted file mode 100644 index 5e3212f7bd..0000000000 --- a/doc/src/Eqs/compute_sna_atom3.tex +++ /dev/null @@ -1,16 +0,0 @@ -\documentclass[24pt]{article} - -\pagestyle{empty} - -\begin{document} - -\newcommand{\hcoeff}[9]{H\!\!{\tiny\begin{array}{l}#1 #2 #3 \\ #4 #5 #6 \\ #7 #8 #9 \end{array}}} - -\begin{equation} -B_{j_1,j_2,j} = \\ -\sum_{m_1,m'_1=-j_1}^{j_1}\sum_{m_2,m'_2=-j_2}^{j_2}\sum_{m,m'=-j}^{j} (u^j_{m,m'})^* -\hcoeff{j}{m}{m'}{j_1}{\!m_1}{\!m'_1}{j_2}{m_2}{m'_2} -u^{j_1}_{m_1,m'_1} u^{j_2}_{m_2,m'_2} -\end{equation} - -\end{document} diff --git a/doc/src/Eqs/compute_sna_atom4.jpg b/doc/src/Eqs/compute_sna_atom4.jpg deleted file mode 100644 index 5d53943bf40b052fe5dc5193db04270c7069a1ec..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 35933 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

    ^TKj};VA(R-rR2bxbe)(@FQA3&t=Yi z8q_DZ%+St-};|H;E&CA!%RE#AGsgZ5A534_}HHHM;EvCTX)ahyDxm59kF#j z|Epd5+rFMKwPg;!^5ync|5<(J+%q1&3OW3EgSQ};#4MwyvkyPcIL+IC;E|%LR>Yp& zhKD^b9Dn*_SLug}6-5Hug&hZzZCh49d}X<0^+RoU;ihAW zuY=~=xN#dCc%&%xL*_VZG=JZrkY^P&uBJhY=Fj8rTjt8z2ire*W!UNcnElcFn0VCPqf_em`|MeM zSUb)>YA638zNw^h-_eJ^^LZn@D-EBYU*#`*Sag%*(+_8i*649tPLpo`u&#~CvQ670 zX#I?xk77Q&s$5naC6e*TxTa3?kxb@;m!U^5A4(|LaQOYCptjf}Uv~8K_WV0{?)9Tj z{+UNa|84AC-MDztwS0{yEsC8hz4cF~MhkWxdiq1hWTn&EoY<_0s2OYGltMv^PGnO+Iuhy+Qhr*gvc5*B`Fyess3{_$~WGGwRg;_Y0x=2(Ry2*ncGT zj`<-Q+paSOJL*>@8r#Hkf7s@Kc*dH`oUIi(vN3kT#z#_13x7mK%rVu;G5FDyEw{Ay z*O8}BQ@uaP2&^@v6}u-x!_^pKL!r(0}v(L;bgu4{@tM{C+UM#l5*kdtHs=kM58DksE8X zkJu^gzFJfJG5MI){{EWkN7jGSk6LZpx;8d8yH4%8DfiK~T*tR2x5KtxDp_4Et9Izv zsrv^HJ0=?4nXj?v*``13ItwR14N(s&jT6^9d}VFaG}+MAn%7om-RSz78no4GYI@L` zr<%K8z6cFmJ0tDplEc8v80t?g6a-~7+;NNxSc)BYdU?f;nl zZPG`syNB1+UEaUNyt{OM?|%8T%j@&fcGmM%lpo(`F+X7P!|ja^GVki_ldaL*@In3X zZI)-}4}CcG>7?2Y&st}888JS?!~7E6luAG>nw(e-W9uW4OBl=yTVw|2`%i5^!Ov&fczd}4iqk5*kg z91=KBH(ZTl(mI<3F1p<&U}lGw{dXd}UttYk!;G*Oz-N*SdUMw|?opzw>UN zdV1u+h8@?PUza3zE_Yh$H9vIS({RSl(1NcUwq~SR*4)`(xsGqCjBBV3UwZq|2T$$1 z&NZ*~>h&m1EZi|ieA_gstf^iXmhs#D)-na9l1v{38ANt4ppW&dTee(W>`pxT)#NSkZxct!HqRZd1e=J|{WB#Fex<5=G z{b%Tjm;R^mL(@k4u{UqD???YO8^z@{K|dxwHvf_T@N6D$dHB5VPCtsxTT7N**~&dP zRaZE?emmcqr|0cY|7X~2oVE31M5%<6=+vw&#!`k0otfJXu9Dm)RkGPj@N{PC42h?P zOM6<1W+qlgmeJ9PQM`8N+gE`I!< zp~H^9#_rmmz(o~q_MK6ue$1Wp`q<=~S)uci<0}4y#oCY|LW8j^n8_ zTa0SXYn-r{EP3$qYMq)*YuF_d=OrJLQS3PK;6vf+U}4`M6W!a5Yf4rZg`SafKfFVx zE_?dZJ(d$5ZQ_=f`OlE*-(RQsWAA?kmO~%!x74TZ=U1Ekq0qgfPAy}bo%M&c?q2Ed8yq^{y1MXQ;KOI}vl5K{u*w|nd6g!4SEgy5waqc-XD=TZMCkJ>AG#T8wWCHa zc5aGfn*ZU7RUxsF1!0cC;z#yad+p^CeLCT3#Ep;NnJbiMeXP@Gotb7aXSe>tGk((T z1u@||aD| R_{ii'} -\end{eqnarray*} - - -\end{document} diff --git a/doc/src/Eqs/compute_sna_atom5.jpg b/doc/src/Eqs/compute_sna_atom5.jpg deleted file mode 100644 index 732731fe13becfbb3e5c6c003b87a90f3dceb287..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14734 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

    l}4UeWq+`sE} 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 diff --git a/doc/src/Eqs/compute_sna_atom5.tex b/doc/src/Eqs/compute_sna_atom5.tex deleted file mode 100644 index 72f5a0fe7c..0000000000 --- a/doc/src/Eqs/compute_sna_atom5.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass[24pt]{article} - -\pagestyle{empty} - -\begin{document} - - -\begin{equation} -- \sum_{i' \in I} \frac{\partial {B^{i'}_{j_1,j_2,j} }}{\partial {\bf r}_i} -\end{equation} - -\end{document} diff --git a/doc/src/Eqs/compute_sna_atom6.jpg b/doc/src/Eqs/compute_sna_atom6.jpg deleted file mode 100644 index 963dd814167b7e3fbec54165368c35fcd9e28635..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17274 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 diff --git a/doc/src/Eqs/compute_xrd2.tex b/doc/src/Eqs/compute_xrd2.tex deleted file mode 100644 index d005602339..0000000000 --- a/doc/src/Eqs/compute_xrd2.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - F(\mathbf{k})=\sum_{j=1}^{N}f_j(\theta)exp(2\pi i \mathbf{k}\cdot \mathbf{r}_j) -$$ -\end{document} - diff --git a/doc/src/Eqs/compute_xrd3.jpg b/doc/src/Eqs/compute_xrd3.jpg deleted file mode 100644 index 19f7aa99b5f79024726f836e35358a98666436e4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4745 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 iO%MB*QlUkQuT1jwxCGA2L=aQ|-vj`j(|0QX diff --git a/doc/src/Eqs/compute_xrd5.tex b/doc/src/Eqs/compute_xrd5.tex deleted file mode 100644 index 2d97a3288b..0000000000 --- a/doc/src/Eqs/compute_xrd5.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - f_j\left ( \frac{sin(\theta)}{\lambda} \right )=\sum_{i}^{4} -a_i exp\left ( -b_i \frac{sin^{2}(\theta)}{\lambda^{2}} \right )+c -$$ -\end{document} - diff --git a/doc/src/Eqs/fix_bond_react.jpg b/doc/src/Eqs/fix_bond_react.jpg deleted file mode 100644 index d63b983230c0c26a7bf9c50b38593bdd65196a35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2427 zcmex=pQIfdgcOJ;VLuhaZ0UQDZ01-+uVvC#9lGbFQ8}p`kv%^sQ98*VX5*PR+_@T_hBl z_WFFL=5e;x?Mj9p)0W#5UOJu`{&?l>?Rl1~v(EcJy}c^&EAutq<4>2W&f08{aBKde z@)&*LpcThHtXc45zVGbp@b$|~dn?Y(y5qK1JmLsz27jaE6p53fthxn%e|hOPZ#P}} z-8go$xPOw>nFn`fEIFgO?wtN#adx{0Z>Pv7T#T3OOW}GX9Fn4-c>9v=CYJ?%=jMuU zKKP64k#)Rx`@&}X9+$;;YaV<0T$`F$=BRBrb>}(rwO@9pSRN3wl5r}qYPn-|V4C3~ zp3oV_Stk#C`kdBc7&)muyCh|^Q`NTRQJTMI9=d*o;ds~2Q`1vI`Jc|Ro3(Re|K$^R zEcBRfh5Hn<{vrX=+ z|D*nu)$S|)&DH&PRkP@#p12)@BDjQ-z0=3Z7x3R z+3v%?@29guP)GQJlKHNSvJ0zp-)IC+=r-09ea2?(Cfd33{_Y3XM)O@$%McLNg<_ia694l>8zh9q!>)M`&Os#MBZ_A!%r6-~x@L|8# zTDf;WUeDg1m3i{?mY-9EW21Sw&pw^bBGC7>bN2~}Z?7kFC!XBD$8Cj9fk>}Nu2aMp zv5dpFT{b)ox=k-vTo%bY`{KC6Wfbk7NA*`IgfT-O^t6AwSXO}wqIYc~IWd}Wqj zv*%T3xo`J3?yB(Tz4rO>U(KjY^#^y-acKr4{6(p*v(xgVtE)fEFT9W)AkOS* zX?6S2cBjDp)z@d0t~&VbKf@WDZ*MtY>E8G6M*L@(Gk3|$-*W#M4!=EqE+FsEw5wJ3->C2It#cOe zu=lzDc>Zgy)O|0tF8s~-#&%4e2@zTckYneTh&mO*e#j|_Ku?_p3C(JZkdUx_Brke`qo>twFvGH{? zJM*Q(S$MPB>_tjz_cg9!2{6iEk;e4OGEG?`{p$3q3#*uTyccU2HcKR(Dx31!Nnb!j zVehGspXKd479BfsQTJe=S@qYhC0CT2mTaC^Ho5NCiz?ZD9{W|@U%r2oGoOK9cHZB# zrfGNIxb2qS{4;TH#p8KfPaN!hzT?B}xt5QYt~z|abdulatCrDAqpS25EUSB9#2$Lx z_kKiD@7}DB19j)f0}LQ>k^(sEisayI=Nm>U#>W6f_ZQb!p-usoXD`VcoyGy6AFaFA2y0>!9r->6%iWgQW znyh)xekNr1w#^}XcHT_M&StRUY+$~ubLdLKw27CuFR0*gYkcXwZF@~C+DJ6|VfL)S08dH+67?N?%6)t#%vy0wI*I_w00 zMxctn)};OZy_V6w=XlT)QHtFFzOd+OQqEQ$5kB(zzk9Z!6ex8dlu;}uWmcl;`}nQ-(L zN6PHJJ%#EO3*MXdeK>x9|EIT?^uDRTm5-}@w~sA9xgs>wEbfK$-Zo(6FVL( zeR+A^s@{g(-vmx=dUAC2FQaDWtdAG}T-Okt@l@>DE;oMOtr07&dfu46yFE|XWmn{7 zwHlLx6qQCMjUW+~pr#8Kla5_&>Ug+#McdM_saztfj*DiMti0Bx^)>5ymxcC0nL<~2 zk6)#)kFWnx(`4(Fu<84ZzY;Z!P73Fm51C$O^kv_jl9=$cE&YwTyNHz@V>oucktPJv-kDhZo69S^6Q%D&h@X%IzMgR z_QGc3<^^W{_0umheke$a{kc;!@0(@5n0OxxU+OdeJD0?dGrx}QS}vddeEolhzJFIY zS=74MCOdAAx*Vmkt13KJ<*{$)$0c{e4r%YWtC;=$X7*(5EaB~ryaFl()vi`ib5aGH zR|QSt`m)+x?DfCO=>ZD2f}_JE4|63)Cr8?_wpM(2m3nY4TTJN2r_GW=PSPS=T$)Zt zyHwoc*4tWdc|L3FjMTQczt(C08D4B&lp*!*OxnD4Umh>Na^7%9?}E?^H+y$ob2HX- tJ-X6+`GJ!abG%ia#HzTkOh5E>Y4(oj@2+LjXPGT;@-+rETju}22>@RNoE!iE diff --git a/doc/src/Eqs/fix_bond_react.tex b/doc/src/Eqs/fix_bond_react.tex deleted file mode 100644 index 9400656038..0000000000 --- a/doc/src/Eqs/fix_bond_react.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} -\pagestyle{empty} -\begin{document} - -\begin{eqnarray*} - k = AT^{n}e^{\frac{-E_{a}}{k_{B}T}} -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_box_relax1.jpg b/doc/src/Eqs/fix_box_relax1.jpg deleted file mode 100644 index d425526046e14d2757882564421d996aa944efb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3375 zcmex=$<%PwSRFvdYWaQ-K{vTlA=3wwZEf2c<1Q((>iB) znCD01ZR$S%88%(|ckkMJ_dESb>ohu6$!uS-r@s4>P8qW%U-avrmOLeqY<7{Z?QHE9 z23rJ5_|D&1veRAj_{V)Z?>r~3og|XneQl1jmuE`j+}3l&H!j3nxWIRAPtEoHtdsi< zd;0#E>W8MxyLfliuTTAF`xy^^<-XIg=cjb;Vz21@wj*bIa*ngOdCESIld_rW`?xmf z@t(;7MnAM<+7(^)e%w}3C@i+~OksAzkD3=vHZ_Mfeav%jd-CJ@6NBllE0Sk^ea6@O z@g&b0tCAwO5AxE-d$%4C-1zv^)PNm%j$&apQ+G{GohZI+`c>B! zykY+_M|R-??nOWR1AhExFgW#O$i@T*M3brzUuRiA3ht>`0^rpJ|4Q0vo3of{~M$B#@jded*AwhnsZmr{P_Cx zO-=`wx(VAhv*=BIoABF@H$$bt%x|B=)Z-Fo!=6ZVY?`X|MB7pSM((XiVH0|p_>&J5 z$kip*1fM;wue`l+GvnGKjn=N;6~#FRJTfQl?~bXCxnH<#emYa?L_xQrp1XF|t@HKk zto>KVF8ws?gH^cU0-+dZM=J&)uk{bD`rFPXzItXDG0!urbw|t9XK8YIHznK-x82?= z_-5&jaP1?X{*=zX(O9@lG1@4%Zj|`d+IGN zI`+_5GV4ZG>5i}F7g{%!edCWi%wIhF`4we{{Q9P=7F+%^?3<&{I&VMA)Yk2;Q`d9P zV!kO^IEigf&L79txwq^dthQM%cYm@x;J+M8s_TSI2{|p61`5!v>f7sbS zBfO?J;lQVW7>C;%jT-EYm!?LX-T!6&%UU=2?ZK^uJJs+1ww^A3bN%6h?bT8I0nuM~ zN!-z}vhD7WU2Z;JEf@UdEKYOTfQXs6#n=q`8s^n z zIgxSWA=w3T&$ci;XIxafjqS|!@XymK?tAal%j;Bn8;Ayw(l2iRTaR z|F|cQYqE28@~h)f2J9a;F5La++_p{YdS6R_X?!ileY1ai?@8Cc>!Wsl<$t)`gx~(o z7CsxldcA)>A9o3|J9cD#tLFUApqc*e$BE1QpLm;Ba)hP0M4S&c?fDf@vRuQ)ST$I? zcgEkl8@5FpfA#iXywMh(gEq|*%o!!#9S_u*ukrrj#DB7)`PYy1%b&i%q2!v}m$9Vy zrp%h^#a0#Bjk@-Qzo&|?*0Z>?ocl>&jd92mgP`jDv!rLQdnSKi?}y!=lk1+=y86GU zndEyhj#p=sm8bl1!*|tp%3^#ozIpzfS`cY}>AGRM_=Po3bt;NKS#B1So0I!}>Nh#% zV)y5g6TLs`ync~dao+#qpK{~A_2FXAXTEnh=9V3nQqX3y_4(uX(}dUW5G^_SIN`X} z}tgY!>2wjQ^7+jWy$m)*%K zWa(z@zD@=sv&o;nTQMIy5%K=wv6qkjTF>~j#$0vfiOrGGGjq1s@4mj2cUGo<-!rGE z_l;}5sm58@IlWhY5~kN@KjpxK4Hvm8ZscDxy_@CE5O2`&Gh5=qHG{dr_thI0tmk9d z(%|hW_xQ=`_}!N4U-M6{KmBwYYdL-yqmmzU;43!cO@A2uI0PDPt&^LcIZr})F1uAXJSj=?3Xx{qHDo6^KC#^ zB!}GLooCe@19!-?J{116Zh@;g-{Vb2`xUz^qW+|)xE=0Z@aS68ede9#%G%E!`E%-$ z!H+p{QuD8D_;IV^)xx9qdLyKTt^0Sr&0x+}`Q>kSU*T|)g|CiY*{` zwF)hPPqO}970Du0=2Yv#wX-Z*;o2 z$<)XHDkbiHGyhub@Hcchf8DllL4Qr(M_$(zQaj@8JNq+={l5!r-1A=iNm$+Fo05iK z)7lwlKbrdJREqSrHnGSGLxb0E_cm`o$hx+&;1koWhg}+qDF(+*Eb3jjCRvI(>VgRa z^9}v2!6!=2FZ(I|`TmKL{|ueCw6SYNuylcV3|@O|$s+ci>o z=k_oy+tqh_kM@E;o9>z2nUuOZN%vOm+bmC=8F!xhKECl?w(-pc1~~>UY2~QxlIOon z+`;wnfL=tM)ydWc(xPWMQ!oE^Kf3(bNwd0y`7^`hHoE1@$+z~r%bv5S=PX0cx2uKQ zKL6kizxJPD3;Ry4AFGQ#@Nw$&O^XvgcJKS7=ax5ia2DDQv@{H;+bY;_FnX!&yx;k&pxgiTv-txXH{5kL1mYhEg@~SsFR&V(5 zCnsjpe+H%8+4t6dKdjqzZ*eXANp5T9O4+^l*iY}?o?so#uv)13;SW!Xr;#5;?+YGr zRjjiz;3%!Q<7tq6dt>_>!8ezr*Ei?QadB~ptC_1cQ>S!J=?}@Ir7PlDKJ3Ze0P^W*-+ z_44o7*lf0HU*+8uc;%RDSFVQ&Z|m3O@?xa|h22}^+5Kb>AKqr88NxwUmq1_I_cas!=~72 z;`!S&w%z?EcW~R>-L;A%Z$uZT|j=xpJ ze#Bea&3~{-BG0#bqv~aO)or@>CwN((KCF}+b$M+W+o6NE99eQ?n?k#V-E2zLuJuKx k*`BMJbjq=&zqotO^9;sKo>mNuZx|R@U%OBUT>sw$0Mm|JC;$Ke diff --git a/doc/src/Eqs/fix_box_relax1.tex b/doc/src/Eqs/fix_box_relax1.tex deleted file mode 100644 index a332360666..0000000000 --- a/doc/src/Eqs/fix_box_relax1.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ -E = U + P_t \left(V-V_0 \right) + E_{strain} -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_box_relax2.jpg b/doc/src/Eqs/fix_box_relax2.jpg deleted file mode 100644 index 8fac42e0fa8305c2deb45e5043f865c3a9e35134..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3029 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 diff --git a/doc/src/Eqs/fix_box_relax2.tex b/doc/src/Eqs/fix_box_relax2.tex deleted file mode 100644 index bc9cddef4e..0000000000 --- a/doc/src/Eqs/fix_box_relax2.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ -\mathbf P = P_t \mathbf I + {\mathbf S_t} \left( \mathbf h_0^{-1} \right)^t \mathbf h_{0d} -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_controller1.jpg b/doc/src/Eqs/fix_controller1.jpg deleted file mode 100644 index 25f381543fda256370cc881e6b57e3b2fd38063b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4832 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 diff --git a/doc/src/Eqs/fix_controller1.tex b/doc/src/Eqs/fix_controller1.tex deleted file mode 100644 index 14f98fc303..0000000000 --- a/doc/src/Eqs/fix_controller1.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass[24pt]{article} - -\pagestyle{empty} -\Huge - -\begin{document} - -\begin{eqnarray*} -\frac{dc}{dt} &=&Ê -\alpha (K_p e + K_i \int_0^t e \, dt + K_d \frac{de}{dt} ) \\ -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_controller2.jpg b/doc/src/Eqs/fix_controller2.jpg deleted file mode 100644 index 178fd5a67eb618a0929d9b1d52be195221071797..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5571 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 diff --git a/doc/src/Eqs/fix_controller2.tex b/doc/src/Eqs/fix_controller2.tex deleted file mode 100644 index 7bcaa333ad..0000000000 --- a/doc/src/Eqs/fix_controller2.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass[24pt]{article} - -\pagestyle{empty} -\Huge - -\begin{document} - -\begin{eqnarray*} -c_n &=&Ê c_{n-1} -\alpha (K_p \tau e_n + K_i \tau^2 \sum_{i=1}^n e_i + K_d (e_n - e_{n-1}) ) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_ehex_eom.jpg b/doc/src/Eqs/fix_ehex_eom.jpg deleted file mode 100644 index 67fa7c092a8f24372f557f1fe086536a7d829b98..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3272 zcmex=$<%PwSRFvdYWaQ-K{vTlA=3pph*u=;v z$ngINgA4;B0~0gI4h9%tWn*Sx=U`;|e}utKfPs;jg^`Jgjf0tu9i)JfiJ66gl}%8H zT~XMOLqtr;F;G<5DLk=o$`zxqM)9Pg;)xeSCQY4o@Y3b~w-`7W85tPt8NS78dIe2c ziXa^P_Qx!KUUsK)P1-}H`+Caj_f|Mfe)Vx$lf{;W&rim`UHkh^`b%UjQ=i@uN)P&! zx4bl;sd;|P;joqk(W<9|xO;7a9^|SlWcE<`6fV+KW74m*VBODzsb$AEyk^NcmGy4> zb{meMrw(mf7vAK06XqoRPPz8f2`~4VkDrERHSE|qlXG2njW^Sx_piD?#qkOLXlP>m z)0^uBo%FBy{~127d|fyz(Iii^Z)Vi51Bbe1v)3~@sQ=aO{1tWjyrE6tn$P?v z-(7rkV9JTz(KEeOxqAGCwuqW7RgLL#v{v@I*S6|#&CZi&-rX?W&3F3Ug+*stc5itZ zC~{t1;YX%-YR&BcKHaMdyxETWWmZxzCglY_xTAaRc(CF1XH%ChU1W5v@u19*2```l-%m zmaUmN^;%8d+GMe3`TPclnm4O$>ito-YDxvC)8spvc_$~G+nvK!oqg}=#Z_F-+Y-Nf zo;$zuQJLhXy9zu0bQk+s>}6oPvSd;pX`kPGk7NdXNa1&?Lc!*(-r9) ziw}!TIC4AQs&2c$c|Tqq9F zq{G^$owOH@T#1xS!#F=HML)E)s#&Jwn#g*5e(iy_+aB*imdYLApSkLt;T0QWwcX1u zr|dJ<%6in0{4-;e)u(lRt*RN^PEC^*Zg9MzwC~cCrGZheT&$<%*BmiiZS(r>p+l#{iwl=- zyR5V0fhteyTIb0vDnI#@W3O;1xPMu{dcv>1FPUO8X`i~i?^);h)gP8y_1nhM=#$Xm zgDw_a)pK8byI%EDGfE^xXvvBtFQcq4{*?Od6*RR`IB{L|v@hO$D|^kR$Mngt9#M2@ zS+V>KljFr7FRoPuO<7tH?{{-!@CEPI1$!nJ%vEf4?XlkRA@|v-Qx5McnmGTwI$C@t zqVs~9-nTG?xEW~|Br3Ppev2(InRX&MJn$dwO)SPvGKuerGuSzS#EpGQ+BBv%{CNFRlL^Q5f`0DJtYh`x5IVKh~*w z`c1saFolW1R@+0&19pCEE_+{#;6mdzM|)=zE^G?Uv}Bc}L2X zLyMMbhUP7QdhWrGHFNrJzV3acVs`DzmP65wIa?-f+N|D^vM=Kh!b@2YLy zY_Z3jD>uY@f4nQ5d*r7^e&|N8)-#4XB3-xHXs$n*;5O^XvzUbClVVd3JmQ-+Ri$A` z^CFIayG+&dI?izLIQ5B0C2qK7sjcWhQ|zQR)VA5F+%-$qH|H+hqJGyah`~$9gyF~JO`gUjOSNT|Nlq2L zu_?;=j7`(+-Zi<}o>B_^9ZGw4UW^IW*!Y$2??uZ(`7p`UJ=^P(qD}_I^!S@8z3Ka1 zVz#w@%8TEjcQ#vJ@z374rz}Le>$2Xne$F44?j-x0o!-Q*vOG@P!G!6cP1z&1sdv;~ z2ZUSfY@R$fcGK^~UV(`ZwQT-YA3J<2P1 zp#4^%jo-mH6Urvuk7nEdCeQu*#+m=7UH&aqEj{t?o3#3+TmBuJckD@hwdDMlx%L}Z zn@$p$UAuNh(Ywoe@6At7IoXk_w{xqIC0jsC84Kf*z61H`DKGAR?9RQEwe;lV>fECY zTuJwyx#e&FE>)_@{_%R%;)IIQg>P1`;9ZyI!Ys+{yI`^6yh-jC3q;=we9*EEe7AOP zM!o~%C7o|KzOATRDSEQc{KV>_W!9?I_V-J@!uIpN+OnzI^w|4X{~6q$PG3`h=;`?v z&lc$)ySMf9HHq@5i`V7skCgAb)%wj``S*=8{~5e9|MuGUp7{68*#6S3`egs)BKy5P z=f7;5f8*M_*vSVEeC#mJ&)yw#DZZa&&l!i$?{;hwkco=&3Novnr^%e|DSIgEtXI&~ zu>Ftx?i$Yy^XuL{@#sF~jkPhRdzT)MD$H`)$;TCts-f=n-IKZVeb}s^sa-iMJ}k1< zi+;ONcFEKokGnX%96qbe>Zmq28o6ER(L3iH7uSW^{F0oHgqoL&`2A)PaO!+B`Npfw z-X}NS=-+f^_1(Qw_e66%Ra6jq$hdLui((a)_dhx>-1QEcx|;1Sm&nXZNyokYW8{TY zHS+UzNI5&Ye|&H`^UoyhtgU&|CCqkY%`BX9CE}%mxJ+2v$qVu`?Ya6VPJ8t6qHKPO z*%os}UESq8OA3Nwta4+vuhp3#R5PWT_gZR7n8@Aety&*h{0a|UlGIn9G>2iuHoI(2 z)|i?voYz*tsuH&+iDomXlycZ<7xcsJ?xubomfBZfYjSqwx3gPrQXvCn^8WyC-ltDrCaQIr)X}U*0Sei-=-~-1hyDF)N=SI zr=qEtskQUclvU|bdOeT#TJ1^A4m#4UqbZcgGM8D=XYI283@h~tjygd6A0O89o6W8=b@>GjhVEL^5^ zC^t%5>-|!z&&dY&35z8-TmAwJ4Jf!#n!4VGdoiSFDRdL61o&Nb*jpaNjE3l zyzuaSuF9mTDlwUmdi?UfXoY)kHm|vEW}C$G!#{QGLKAIYwgLBBV@*5uXTCX zV=?KqZKiFtJGZZ$7%qD(xhN=L(xFS+_H^9vnlO3sjo0o;`^*27U97EQ{%*0V@OSm9 zD&@0#w#`Y+%Jp5bG(*ujBWjY{7spj!zYFd3IB$6S=*Am@Z_7IJ4ek_8nriU4D??mh z!lbG4tXsF31s}2S-}^K?D`=|pq#J83Rp*{|eJ7RXSa@u1v{uk0k!5$hJMIhdHC>pz zUU{u-ldHa%w(q0Vb*ZPMQf#xPzAl)uRD*5agJnNo$O<3LlKsB+{Tb#6eTlto@5_>2 z7c|JuI#RB*^unu)CtFu?MSF89=&~$SS?bVtFZQgnY0o|3tDTmCQ+aORX*gpReE(=F kXYlG$Mw^Pi$=#W*HQSdpm40hI1#OKY8ulox{r_(Q0I*;yhX4Qo diff --git a/doc/src/Eqs/fix_ehex_eom.tex b/doc/src/Eqs/fix_ehex_eom.tex deleted file mode 100644 index 344ebcef76..0000000000 --- a/doc/src/Eqs/fix_ehex_eom.tex +++ /dev/null @@ -1,8 +0,0 @@ -\documentclass[12pt]{article} -\usepackage{amsmath} -\begin{document} - \begin{align*} - \dot{\mathbf r}_i &= \mathbf v_i, \\ - \dot{\mathbf v}_i &= \frac{\mathbf f_i}{m_i} + \frac{\mathbf g_i}{m_i}. - \end{align*} -\end{document} diff --git a/doc/src/Eqs/fix_ehex_f.jpg b/doc/src/Eqs/fix_ehex_f.jpg deleted file mode 100644 index b74a28d907d1682c3a95ba59cef84f6914ae7eba..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10352 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 diff --git a/doc/src/Eqs/fix_ehex_f.tex b/doc/src/Eqs/fix_ehex_f.tex deleted file mode 100644 index f6ffe1d720..0000000000 --- a/doc/src/Eqs/fix_ehex_f.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentclass[12pt]{article} -\usepackage{amsmath} -\begin{document} - \begin{equation*} - \mathbf g_i = - \begin{cases} \frac{m_i}{2} \frac{ F_{\Gamma_{k(\mathbf r_i)}}}{ K_{\Gamma_{k(\mathbf r_i)}}} - \left(\mathbf v_i - \mathbf v_{\Gamma_{k(\mathbf r_i)}} \right) & \mbox{$k(\mathbf r_i)> 0$ (inside a reservoir),} \\ - 0 & \mbox{otherwise, } - \end{cases} - \end{equation*} -\end{document} - diff --git a/doc/src/Eqs/fix_eos-cv.jpg b/doc/src/Eqs/fix_eos-cv.jpg deleted file mode 100644 index 37eeac8e2dfdefc78688b40a5f64393296eb5810..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3016 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 diff --git a/doc/src/Eqs/fix_eos-cv.tex b/doc/src/Eqs/fix_eos-cv.tex deleted file mode 100644 index e084bac9bc..0000000000 --- a/doc/src/Eqs/fix_eos-cv.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} -\pagestyle{empty} -\begin{document} - -$$ - u_{i} = u^{mech}_{i} + u^{cond}_{i} = C_{V} \theta_{i} -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_eos_table_rx.jpg b/doc/src/Eqs/fix_eos_table_rx.jpg deleted file mode 100644 index 0172281b6ccfb25e31b923f8e0a2c7f027812caf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17367 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 OkQuBm<7<_#hv=|r|I2f21g&3F_7#J8C z7#SGaGZ|RGYz7831`uFgz=)7tzyz0lw164TwgoBt|BzELqokz3N?$*(ST8XpKPgo& zIX_pwBC$ZRwL~E)H9a%WR_Xoj{Yna%DYi=CroINg16w1-Ypui3%0DIeEoa6}C!X!>#g)tw6&1N(x{lCE2!0 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 diff --git a/doc/src/Eqs/fix_gcmc2.tex b/doc/src/Eqs/fix_gcmc2.tex deleted file mode 100644 index fc4d90355d..0000000000 --- a/doc/src/Eqs/fix_gcmc2.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} -\mu^{id} &=& k T \ln{\rho \Lambda^3} \\ -&=& k T \ln{\frac{\phi P \Lambda^3}{k T}} -\end{eqnarray*} - -\end{document} \ No newline at end of file diff --git a/doc/src/Eqs/fix_gcmc3.jpg b/doc/src/Eqs/fix_gcmc3.jpg deleted file mode 100644 index e87764afd9181dd6c4707c0a33b0a80abd2170d0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7437 zcmex=Bm<7<_#hv=|r|I2f21g&3F_7#J8C z7#SGaGZ|RGYz7831`uFgz=)7tzyz0lvVa-Rjsq$D|BzELqokz3N?$*(ST8XpKPgo& zIX_pwBC$ZRwL~E)H9a%WR_Xoj{Yna%DYi=CroINg16w1-Ypui3%0DIeEoa6}C!X!>#g)tw6&1N(x{lCE2!0 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] (v1) -- (s1); -\draw[line width=2pt, ->] (s1) -- (r); -\draw[line width=2pt, ->] (r) -- (s2); -\draw[line width=2pt, ->] (s2) -- (v2); - -%Spin -\node (s01) at (6,6.0) [draw,thick,minimum width=0.2cm,minimum height=0.2cm] {$\bm{s}_0 \leftarrow \bm{s}_0+L_{s_0}.\Delta t/4$ }; -\node (sN1) at (6,4.5) [draw,thick,minimum width=0.2cm,minimum height=0.2cm] {$\bm{s}_{\rm N-1}\leftarrow\bm{s}_{\rm N-1}+L_{s_{\rm N-1}}.\Delta t/4$}; -\node (sN) at (6,3.0) [draw,thick,minimum width=0.2cm,minimum height=0.2cm] {$\bm{s}_{\rm N} \leftarrow \bm{s}_{\rm N}+L_{s_{\rm N}}.\Delta t/2$ }; -\node (sN2) at (6,1.5) [draw,thick,minimum width=0.2cm,minimum height=0.2cm] {$\bm{s}_{\rm N-1}\leftarrow\bm{s}_{\rm N-1}+L_{s_{\rm N-1}}.\Delta t/4$}; -\node (s02) at (6,0.0) [draw,thick,minimum width=0.2cm,minimum height=0.2cm] {$\bm{s}_0 \leftarrow \bm{s}_0+L_{s_0}.\Delta t/4$ }; - -\draw[line width=2pt,dashed, ->] (s01) -- (sN1); -\draw[line width=2pt, ->] (sN1) -- (sN); -\draw[line width=2pt, ->] (sN) -- (sN2); -\draw[line width=2pt,dashed, ->] (sN2) -- (s02); - -%from Global to Spin -\draw[line width=2pt, dashed, ->] (s1) -- (s01.west); -\draw[line width=2pt, dashed, ->] (s1) -- (s02.west); - -\end{tikzpicture} -\end{varwidth} -\end{document} diff --git a/doc/src/Eqs/fix_lb_fluid_boltzmann.jpg b/doc/src/Eqs/fix_lb_fluid_boltzmann.jpg deleted file mode 100644 index 9d82b40ecb009745f6b984f5092b42008a057380..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4643 zcmex=$<%PwSRFvdYWaQ-K{vTlA=3ww-oXp55 z$ngINgA4;B0~0gI4h9%tVPj@xXJq2|e}ut7fPs;PiIItwiJ6s^g`0r^teS;YkWEOD zU0BJ`Q6x~*D3L>4IjAr+sd3sBF;(M*rXgWv%@e0g-E!&j|62?kjEoEn_6&cgbr1!* zIv>RwpDT=>krsL&eBLx?>;9wr?tJ@I<=Q#xxaGtxLXQ~jXKcxL-@kG1A|)K)S^XCC zzk-MB-|rLt&oJ%iWkDn$n%|X{`$=Y*zasNtgQ@A0S{)?sUD>#QS!Sp0uc&Xk%o^8z z*?WA2<*v`_^Y*Hnr3)Q%c%d$FdE&IMvx2-M%+GwfE$r@=wg> zpDwcTHqx$B4_XtxaMo^_6K}3fJf9wr-Q6v7edF2Us<}5d-u{{qInnj#lgw0YyR+Q9 z8@bhI?VfY@g(uItF1PPLvu`|`e?`-yqigHr^Kp}B8+RrvlnD1^o;Y1~R#SD2^s~y` z&ZSG&8VPR~h~Z!;v%c}U|C6-;)17jvGe!3cuME?^a5lCtr7YXy`Q{a-N00Vp-*~oj zuiu-9x4*XNoZ41wR=DSt4xgW+YR(q_+2ZC7nK=_1QrEq$o;UfK$?pkr{7+eKik2T) z7aHI4A!fbC#>j825><=W9WR-=w76NhN4{_Q&b9ZC{R?i3duq1))b%Gfs=n--b~t%u z8hc-NkKxvH73sm<4wc2#bLZwe-;9_jC@3m^PSg~Pe$Lcd%O?-PdnI4Lm^+|cUZ}G0GS&T1VS^Zx7NJ;B`XUwYooDX)! z1tx8N%VqG@J+|+qvDb4pcL{r0|KjNVy?<7f8$FFvO4{L9`To$wrPK1frkM*@uaNpw z>oeg^Ap9&+GU< zuX8qJbB^1=Kg0niBCT1*+r&K)0_N^Z5o4eL3!@nZ?@C)Owa$6i#}H8ctGW7 zqEa(EkC@t))9-6Gxf|SePJVHr;O9-b$8oO?&p-X?#Lu}hcI@J9+daRY`JTSH%;U+L zduz=v+_=LZcq6}XU;E#wYXu#il*jizzNyob%U2sU>D;yXldg#~{%25){}8r1^M~UR z1-{qi54OrHpSW0kS2*Uo{FNP(|7p8FJeKsn^L|IsOuaiRkIpX2s)*XEUcz=;u`+q> zNo9`8SJg362b`UwH_7-f+kEi7$9uUN=O;U}|1-SPlW%M1yM1Yr^X%=>Q+E8>r8aHj z@jEYsH+jZx+j22-t!PK=b&)mv$y?lRxgC7BW%|!Dt*Ixoe1j)gdCa}^n2+hp8TH@m zQ&iW*nh$ER#a`Qe;dvqdsb$sh&BW;6CX=WL7MS8Ov6fFA~&z9G{RS>8aRV?=BGZwG$`{O+2 zWZ6?co!gUx4_#epy};}y_i5QYPYLJq!M7eLFMoOasr`EPzdZuB&fI?R#~sPlS8vXGGBs(|9G`}b7Y<%e^Q`E3fXqE;rNAi#eDV2ld5%A-In)!=J9>+alZ+U64_FA@t3YOSWn#+dUDD0xZ*#v zYVuFLvXw1c_Uh&R+*kIcADieUaa@&+_l=GyfS* z&dmREI{nzsI(7TXFE6e<5jb_CXX*7He_sW@5HOLq(a9_?e92yQ^IGGz_T%C^{}glg z*ncRBnJyYue@%aN@4Ngj1?irDWkP=zt`{{dFTQ6}z$0VRt0MStV&6tl9z!#U zCFwDKDmy>VKNn;Bh4Ip>Nlz4y-#Pjy$Li~BbLN>chgQ$Kl$;(sSNq1jj_>Pkzhs$f zQlmLN$31Ayx2HMh`XufuA2HY!KH=gfsbfsf;8Y2M0C?~Kh&ACWqmD6+o>9{Y`L(4 zPKiP3%}MbwdF8=1%f8+B-*&5d-BMAFo9z;BmM%|~_%>tdq}NJ!9voT6O&P7x~oc zS#F29pH@_6OT{=##5`j7!64-S!g^io<9Nd(Q6I8rhjqpUJJ}O$oIXyL7l})q z|81J&s_XYN)i!hJzJI^oKY0Jt1@jZabXZC&+TX^`X*=`I@Wz9}Cu{vLZnnNzu=SIG znRBPQZ~lFUYQ59PR^DjabN&4>$%*^^Gguui->;GF(;+|M*o&Mp^_90|T|Ez`YNr)W ze3Ip!Wsy>R>)Oq=DneB;QJyIc7EDndH{O}JCy88%SQp-P*K^gmdn=apUfjFCY~mvO zPg?UIv`jw!aG5%H$?lIlJoU|Y`0j_#jQ$bpUeBK$sbH^L?SJaphjX@PEbIl=ANujm zo;_)*ypc|s)7g{KPY*qxZgQHVXS(g)D8==RzwQT{mBxN#Z@F;bhrf5r;k>u2YbIN> zMt_gBeq4Jp*GIM}lbM6>Rp;i+lv@g=6th@Uei~6;k)4b zi;|slV|R5H+OzCPmwP57-x2<>rd+;xqgVe-F>A%NC%vB@7N4G#+T!Lt@7`L0>kWVN zSI)L-E*8yiOsF`{_xO6c`A@ydGpEv?Cf8g)@#E>{w7P#2b()lp@e17S&0oSiuP~WbV*^jgGjZWQP`{=sFapxJc zIAm0JmWkz`{uQ?QM7GSmhv%oAol$x_!TEOFx^+FPw^hiqZ%vCft4NofR~Z+tGAUWH zc;2J37|*ie$Q-+j*TpJBtF^#2T*&HouzZM@zlb@lQ3IE{yGYHaQ@xxCp@Yz+)$ z4E(L%IyzR?nOxkO-FUjJMaaLHzi3&U#A4~1`QFxQ)l%$5F~@8d@Yk)?mOb-LY`&aL z*R!y>IS!56cyBJ_X>ohN9TQWX@h1CMtIMMg`;C7)6|HkJc{L-))JC;Zs_eR_qS>;G zzuWfh|1&M?XY}*qo`uT|4VOks)velbf6B`@Hc}T&_x|#piP7QW3E4HI?NCcOGI!;y7eb#vs#`+imzFG|)}{BhkQ&Kqw$ z;g7p+*pkvsVx|8XgwEvh%-*;A<-^1E1)+_C4$Z=0`-+am?VP0f*5z7ca_k?=?t0}r z_H%f*ugFezc)xV7@s*fm=CV^)f7$6Jnjij(|I?a7Hzlvw_RZnA@q49CcEo{WCZ=np z7(xSE;S#o_$S|gt+d8f?OO6L=lYhKn_d7Rv{JWR~c-^(p$f z7~jLaRrmdiZ&$rrx=1JN^})O~S9P6bzCKG{JWW$d=K9vdu1n;O2$U{m@B8@2UVhE1 zA6>p{j(=&F+irWrbm1D-b1E;_GA_t>;N@jyH$GxGGcMeHQpBv=xgl#_Ei$v+7c7k_)*rQe=9#os?59dtlIe0yOpYy47~F$<%PwSRFvdYWaQ-K{vTlA=3ua6_`=92 z$ngINgA4;B0~0gI4h9%tWn*Sx=U`;|e}utCfPs;jnVFf9m6?MZEYHZq%)-Db$R?!7 zE^O$?A)*wRD5`8Ers5P7Uf4Lv#5p)AxoP5*g_p1Vzs118$jHE8&+si)(<^AoQi8

    hYrQ3%vayG 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 diff --git a/doc/src/Eqs/fix_lb_fluid_fluidforce.tex b/doc/src/Eqs/fix_lb_fluid_fluidforce.tex deleted file mode 100755 index 8433c9264a..0000000000 --- a/doc/src/Eqs/fix_lb_fluid_fluidforce.tex +++ /dev/null @@ -1,14 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ -{\bf F}_{j \alpha} = \gamma \left({\bf v}_n - {\bf u}_f \right) \zeta_{j\alpha} -$$ - - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_lb_fluid_gammadefault.jpg b/doc/src/Eqs/fix_lb_fluid_gammadefault.jpg deleted file mode 100644 index cd10239c9b366fcd33c079aaa7e0ad1c4ea0e829..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4793 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 diff --git a/doc/src/Eqs/fix_lb_fluid_gammadefault.tex b/doc/src/Eqs/fix_lb_fluid_gammadefault.tex deleted file mode 100755 index 1af82c4972..0000000000 --- a/doc/src/Eqs/fix_lb_fluid_gammadefault.tex +++ /dev/null @@ -1,14 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ -\gamma = \frac{2m_um_v}{m_u+m_v}\left(\frac{1}{\Delta t_{collision}}\right) -$$ - - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_lb_fluid_navierstokes.jpg b/doc/src/Eqs/fix_lb_fluid_navierstokes.jpg deleted file mode 100644 index 0a1c10414120eed3ea5f2f82db596d7eb60b978b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9311 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 diff --git a/doc/src/Eqs/fix_lb_fluid_navierstokes.tex b/doc/src/Eqs/fix_lb_fluid_navierstokes.tex deleted file mode 100755 index 41ca4674e9..0000000000 --- a/doc/src/Eqs/fix_lb_fluid_navierstokes.tex +++ /dev/null @@ -1,16 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ -\partial_t \rho + \partial_{\beta}\left(\rho u_{\beta}\right)= 0 -$$ -$$ -\partial_t\left(\rho u_{\alpha}\right) + \partial_{\beta}\left(\rho u_{\alpha} u_{\beta}\right) = \partial_{\beta}\sigma_{\alpha \beta} + F_{\alpha} + \partial_{\beta}\left(\eta_{\alpha \beta \gamma \nu}\partial_{\gamma} u_{\nu}\right) -$$ - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_lb_fluid_properties.jpg b/doc/src/Eqs/fix_lb_fluid_properties.jpg deleted file mode 100644 index 3d70cd7667461b8f4f8c96c5d271ad2662e88bb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3471 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 diff --git a/doc/src/Eqs/fix_lb_fluid_stress.tex b/doc/src/Eqs/fix_lb_fluid_stress.tex deleted file mode 100755 index b4e0982536..0000000000 --- a/doc/src/Eqs/fix_lb_fluid_stress.tex +++ /dev/null @@ -1,14 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ -\sigma_{\alpha \beta} = -P_{\alpha \beta} = -\rho a_0 \delta_{\alpha \beta} -$$ - - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_lb_fluid_viscosity.jpg b/doc/src/Eqs/fix_lb_fluid_viscosity.jpg deleted file mode 100644 index 1816317ee6a908724a969464c4bcfbf85b44bd37..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6522 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 U-IS%yPE&Bj7LNVB^8arF0FPW@DgXcg diff --git a/doc/src/Eqs/fix_mvv_dpd.tex b/doc/src/Eqs/fix_mvv_dpd.tex deleted file mode 100644 index 685d527763..0000000000 --- a/doc/src/Eqs/fix_mvv_dpd.tex +++ /dev/null @@ -1,21 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - v(t+\frac{\Delta t}{2}) = v(t) + \frac{\Delta t}{2}\cdot a(t), -$$ - -$$ - r(t+\Delta t) = r(t) + \Delta t\cdot v(t+\frac{\Delta t}{2}), -$$ - -$$ - a(t+\Delta t) = \frac{1}{m}\cdot F\left[ r(t+\Delta t), v(t) +\lambda \cdot \Delta t\cdot a(t)\right], -$$ - -$$ - v(t+\Delta t) = v(t+\frac{\Delta t}{2}) + \frac{\Delta t}{2}\cdot a(t+\Delta t) -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_nh1.jpg b/doc/src/Eqs/fix_nh1.jpg deleted file mode 100644 index af07ea3a4b3a197d6b415937d1325a7c2a5a4a00..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68243 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 t$<%PwSRFvdYWaQ-K{vTlA=3w~Ac$AS* zkm3Ik1{nrM24+SOV1NNuHg*Xi^`fNP1$!D6F+I0D?zo_OQr**8CA(G6{LDB~ z+&FEmyv(WDldYvq?|W+^_ms9yfTdKX>s7!!NsUoDZvUIeUAa zL$<@)n}sU8*;((S0&O#vXR9PkY<#%MVC&f%_d4tx|A;SA(z*ZAa{lDrFX~h8t^0I4 z_>xKXxA`3>6Ay`f`=`9Wesk8#BZYz=|EYHzI24t9>|)bw>)Nd{xe3?5Xu8Hck2x=V zIQ!zp>Fo+X)<^d(@n0KxsZpmtTSCVD#oKcXwg2j#CcA{56Fu|MX4|p2eP%K(Mvrv6 zrrpfjyij+_273qj`qs1dTePK=l$5mY8$GeqvGZo_J@RN(itf|5p3HTdORp~OG2&F! z)5|Fmeq@^+Z(o|6UYMZIU>)aR&G2vQuP$@t>8a69bF<8i%yw7L6%E_|IrsOS=R4Qr z{d3rzey)+>_4DrM8}Ias6-iv*vvKn2sEjB1*$-!_&v@GT_{p=q>)4~^%s5#@8GB#( z%bzHgj`3O>bNkbkzsgz0-80PCPLv$C{kwN<<|jw>8^WKoUr+cd&DivG%a5(MeolXy zZ{{A-#gntC^R~3}yr^f}T}&);R@dkYxtwHu|{%+eAJb#C$mpWcocT* z$X$Hjt5OgS96n7?D0u&8%M)?MmGS(3iLcK&r07&8R_}i*cWg`c`AO_AD;Io_@$+Bt zXV&uIou!s5AFZ17PrYSM#)0Gf|F#wI^_*vanEChZ@;}L2*J<$dYcx&0nYEjD{+wea zDb12P6L){L;1$?oud}-TfXwVa6V3m5Rm)~>U+J2;A)>*mpu`7QE4gZ*sdd9T*{{iutYs&f2{bm40n!)z$TGmN{>chUHe@d&@ z|2ku^JNA4|>)w9d8>+jQ9bO)f%irT}-}5vkUi!p`%aR*^N}bur+;Q=3!M%>37S)2E z6k2bK{xZ5hTVC|k`<={EKUZ%Ho2i_={Z`D~H_VF{)qYv@^S#Egf_?Ino=P_BUs>UL z@7s}k&rdvZjyTpod(Lyy#UB+No?7;m_x)|opOTnyZQ-=Nyqvz#c@w{=&G>dmejCHL z=`Z^Vu4fi}a69p#d;Zgne|>DcrzIHf@G`zI>z%#Uo!v|O?k{niWN_W-!1b-m_a4}N zxTf#nCaZ!yljq)h_}zHAMVh>9;>MYop_47Od(KGzSYjW_X1j%*?d9=vb0o@Fyb-s5 zGShEz;477yxXr6i_vX39)RcQ}c=6kM{>ypiF1^j!y5vtBqmH`sWyLwiKE>Sk{>dg+ zA1^;)Ytqq5(?t<)YM$iO^q=UTcq2+n-`e`fOOnm&g01$U-k>T`{{Xn{~7#`ZL#~Rc_?@H%vz0|Vx?c!UTN-1(0&xjx@?Q(Hl4kf_deb- zao@46%iV9ZZqw)ft`)Fc_w=^~E29+es$BMvIL5zc#}CH3OIyRfdaS*)nRnKuEmoEb zE2`x#f98|ph?7{eOV*w=&ZJNHYidxycsIVQFmv6c+S#_9vSRz= zlNXJtg)NYP2q)0N%C+xTGb@&lh1 z8TOn%e|^n<_1XRR+awDk{-lX{zTSPgHaW>t&-O`0=L6FvrcW&X+JHDTb0d?Gn#|w=2dg_AS-j9zMrY`Hay~;aKIGbAPS3Ye zOFI^IoUM@UxJ;OX(9U^VgRbw~f8ZV8{mf5n+Zb;Ml@$D$-}hInXbv}Tt@qrbjjy>^w59msi%|ufCFKUDu`L)mJ8MGnb#R*k4Mu^}~rD zO34v2&urLDzPC4UNM~gJd>g%M`3d7W%NJd%NSAt8Gbzt?#_{7Whm+-gtiG0gAp72L zy*~#T7v6ePy)W)|l)76*^ABG(uCt5 z-kJ74+i92XFDerGXNlnT-37KsFC9C;?AG~KiZ|m1!@P@oUuf_z;pf_U{#W4i#}y|P z)13Uhj`~M`-|j8aJ8@0yFaGX+d;iPKz4@YUuo$E8J z&m5gMd#?PXOULD&Gu|rQq*S?;!)mAQKmBy^69zl}I7e2^3p=Lg5vzOgo^p-c;_?-H zPh8M{&rqXy_foC()0^|W59k~{Wgr=2SGCtNGAH7=FN^TBru$*$whMRFx0eauF>~9K z8&VZ{a^3Y`Mjy|VY4<%__gv-i$MD6mQ{ob*xx22o_wwtDP46rJ02O{_*fuS z^5Rz_;xJr#Vu#Ecb8%w z*;UiT4zkj}Iab3@b zC#-VeQ_nyAbYsuG@(GbA&$GS~I+Wac#E9eYoeS49d*q}%r9Uk#-0OJy6VE({k7vA> z9KU$_?@Y;QQ{J2R6m`7uy4kjRET86V zovVI0$WoVG)^>MBjUnIN>Ir40i|=2#Iros2_UzexuHG_*6*KEr@|f;U=HpT9NsfAW z%e#Z&&Fi|OUM07?!XMeh%`@E)AhvjQ9Jlb*)h}l5m53DP{--W3aLjb~{S6ZlIU%d~jTqvD$b4I}g`3WKqvQw_VuHN%c*S_e6pkQi6 z+@zReU+29KvDaC1cGCXXEpNk3lm++gC`mEMcq4z-puGC`-`63L&tt7pf3NyDCe3FU%Yqg^8?>+?JQhnZaBkg$M2uQ6E`wj%cdN7KIS z*r8irmz6N7bIiIRb)CUO{ov=v_it8wp5s>ZF1W+%aUZ-Wci?B(vT`w|56oMiFmK?09lyHot=O&oPN$z1+tO`+YK%5cteUjvq}n{`S6i&yEuXMAZWsKezSSk@ z*z@AK0jp0KTckaD@jyFnwTrawlv_2Qj!7H5mFM`f@P6jEuUj`oy|tR%d+t-UXvGwZ zw7;FUv%=P;+)dr}rtSP{9lLqEx49T@-~Ie`b>=#ymlH~l1x@{;&{XZXe^y^*k5A$6 z?!z%r_5zm{?8QFZ}eGvMro~-f?n^ss zUF+G~tomnOhyC3!m6A=p{dL!Ew$~e6ScjZ+=*HeJ_u!hi>*vR3q2+u4dY;nOS^PHp^nQo4E8 zw}~4ZlG9PQ*;?D- zz;WA8r{1R-_OhO{j%B9@BT9wXzRU< zmwGzQO0egEPvMT0#U?77>po2U9FhI5+*?yn%yg0ODF@Yeyb2WsQc=@ok6b?R@lP4I z%=K;4td@jox9{G0$l`{?1^+WI__g;67JT9|dTL9i{COIubZ}D zN3mp0ne5j2legTucyq(4iyq(Roe%scb=`v3JpCc-5vE5{HWT=Zuy>Hp?MgL#wsZGh zw@nZA?5|Agm+t?ev+DRa&y;$-^bIfmGwj?t>#usgzDQtpccDD>?Cd(Un*0RTMA8G`(&CQvb$fL`XFzNY< z2kiHrTTK4#^{QL7Z<^b2(O;WvkNak)WvYM6Emb=CZ-SZ8m(@x8&Yrrlyk2+av80WB zP2tRO={NM}rJH1~mz!+5JSTIV+&P7vHItKeZ9TMOoxJ+A*$kL$FrvHn9JLdBAwGyaCufe6W8)DtF^17CHr{iZ24{J zXQ?eII+O2yQBT9H%NBp`FWY54fA*uoe?oiFgIDMCnmez}5812F?l_uURP@~FLz4F4 zq|1-W*J_r{{jl*qv$LoAlU=`NpDwPEUwV@-I&Yp@w#AKj+ZlD6m6Ix1+6?>N+%N7- z_{4BiE59Y~iKGr|PP@|ai^p$n<|*d-x~yj3^kPTd!s6&B!t0rzEDsbE6s!NzbuQ}h zU$H0KGc2}!x#}v_Qa54N;oHm{e;g;s-&niHpEta(uqIr73B%gn<)R*2Og|huaH0Op z!m8Z|Hp+TEh~!hB$vQDIqeOU1?$u}c(>(59sXcy1$S#}lm)<}BkTXxL^snrbJ}!Ow zgX^KWof|joc%sd?!FkTzJ#8-!{GKLId+X_6j(2mv{5`8%&ia@|a1oyxzx|6<@w&h4 zzx?{U>gGPfwv|UM<*d@8j^97#qL{3j_%5SH_p;m}2R+4Lb~a$ms4xz%%|wSC@AoZu`ybA$ik*FRWf zD_LZ<=jLhJ+3QYwdijaM{*$>^b3N9c6<-=RwQO#i+u0p$Og??LJ1eF17)(qr-nqNa z_2BAf`o1#jciMc@-eI_A;#Ya&v*9PMH89_0U-o!``Tm4;8k^o#{Abuu_47dS8rz9! zukRd)Rlj+kVRQVq_Tviw8J7S0zGBhS#S@p7oqcsR$1HN==dN$F%y%p?Gzz%<0uVkGq_N3>aax(vqTi0aYpOCWGw+cVA_jtg; z+xu0fCe~J+pL%}o(+yj;E_r*7IdPxO-28Y|;mfc8Y}Rb-`p=+u=<$bZ&y!P9t**_t zUc{2W&FPuBpPUWv>+@5Sk*f#Swyzc`KkY9Sw-mmynR0l?Ijw7T2euryQ+nyKUZ5b8 zedqE#=6c(o+=pNC%4?o+JW|0HcTBA6&hm+&O=nCMCayPKP`=)HpZWv`!R^QPCFW~C zs!VPYKWltjrf|#7_k|ZSm{TTy*ZR-E^7PBkR!;qZV^3FJ&*=QXFRzT4UoQGRLl(wlPr zJxkA5c+U@>^KtUmuAl?ICPb*)9Th#|y#dkd2ocwfQ(q);` z0y|sRevR;sdzOET8i_3s1-D2<=keC8s`lmQhrRcigF` z>+}2hG8Ot2CM>*tdIxure8%>!Pm1OH_rGRteDc@t{m0$=R`30%z3qCS#nx4uu5Rpn zW^~w?r^xV*v5xaBw+{O|_m1evnV;U_E_?KN&*6ubORF}vwQarQZmf7Y>Y908ZPDXp zTh~h4F+0dH1jX-)m-)}oTsi-%vF?9{V_`XJe%q48`P`P2C$;6hyLM-(X{6hnsOm*C z*H+gwuicW9(c8pz)@~A?A>ZtqnMxizziF7e$H}Gi9{A62vGPBI(KQjZ_{on8%VUGi z=G>WN!W0|MS#+kZe!7TXrhVHVEpz5)79Ex00V=h2E-ruCG$kaDuiw%5Etc(%gOj)4 ztr~0hD65MsFC}WG)~vN(d$sRL;dilDS1q&clYa_rU3dNQTAkT1L;oJ_ePGkM_?-Og z3|6+njJ#k4DJeUeC$o0F~(ymXu`nb=tnX`A2&Bk?Qdzc<@GS}P6 z)*el(VQ>G;lOApvZuUeVAtkNO>Vn&??MrK>C^nfhN;@yin7sFh#oX=gPim*n%kM1i zSs%6IKZE(k=zf_vwym?SYW`hnzDm}Tx3>3}6yKKvvh!cA+vi+8C2iMMbBP7gV&dZM zO<&t;>%59$W>uypo2uj#|25-?-Eisd&d2G_?$cKVN38u)c*-Pg?&N)cB9`+0y1a8y zw$Vgp8JXj`hp$w8SFgAI86_@r_{xEYT1gsJ_rq2TC-rz6KT%xEz`%V{A)`9qF<_Tt z-}>a~pWpeY?0D`wzm~)L?Wu3SLKk)^aTIr0O}~Ea;I%&)6;WC1Za%1yyE-%H=EFH< zl}{^cCVBR>o~!P>S*W^OWxjP>{m$nM|CB$@|Kub8E3|Kq!L{|WRUh4X3=NDd9%p1n zTrgo^KEO~jE&R*E{Dp@MEH^JWqpyABes%xmsM|hi=O2FT-cuSWh|CPaxYOfFO)$K0~Ue}(Jx?p(aRq~4Pg-&}ySA}(MbmZ~nP07i) z9L4aBfx%>NYPC}DrBmNF_OPBS?rV1VuJZTvqp36Uf}5VE|C-=0ozi zLj3Y4x;wo*e);H=&EmHOW_ewSID1@Dh28R#ZI86V%cXaZyF0vi{kXO0j=KKBq-%1O z+^-@^qo*$Kyyzd6_HRm&+gq_6^^S6m%BSYJxK626jQ)CNy^o>ci_`YzOVhVMzZqwl zS}4C_>*{dV(1#*=Ay4kSJ38xS~m9NN}Qhkz3<1p``0e5^=iNVPqco8 zt@g=}HK83^PjtMaygr}bcVez=#}hq;>OZ>W{YRsI+*6ZLlar}2vP(DF<+;3q@$;$g z;-1=DAMZS;dOXhN$A`^&w&l}`!k+$A^VjB+>XH1Jb?Kh#N3PP>QD0(iD)917^7P67 z`|(L#;VwBlO}jN0noY0B&3&+R(&cD1uVYSSN3$Xhc5O|cP;#7sV^#!z`Ht(&@A&iM zpOnURe{#Dv>9Ed8k1H#l`F-1cZAM4Z?OA1YmeLR2$j`gFyD#xoLcvr+5!?LLp`9Du zRA+t?xYoeH`ecHM?e+yr-~;c1f`Z~~;oR+~CC-HlJN@hsl-wLU=^OLf*E?kMoqsVk zKeY*ZuW&A)bk6m3`PI77dPmJx*IB+k^)ljp@O{@uLeX!3uC3>oXnNw+Q@uy3>)TH8 z#9sPw=d>Ez=>^xfp3BePQ{&5*_AmCfoYS+1Hg$T2#}$tpw_bBXW!lkhzWmHtl}k!C zom@Y?_}=5SbD7xAO}V6`bv(@Cz_VJ@CpIwxH;YVEy4ZymoZPzO?r%A%`lP=v)0J&D zFQ4J_r(x6CS-oP9b>A9BrXMs(sp(G1zWrPLeQ?6FX**JH&0#vGwXUk{S3%T?6W@-; z$X7CC%inqUi6uKd{kFTw!yj_{3;k@vS=*0&S!A{K;E(y`N-tF_t!pM(9N%txPW4>j zCr?#xJO3pM6M0r%a(G*zcFm!oK785ApZDh1D(&2t)vA|&#-h|t<#ph0?cRfSNAfl^ z6zF&7ckeuSKtjXtv}Wbu*fvy?xCG&YIdskRZkcik%PlB43< zZ|`FFWX~zu^WA%M&GG9;AFocjJL%Wj=~qj7_sV9fWUK24@%y&8e>4&Dyve#a`qTMR z{%HX(&hjli>(#1$qpM}jVJmg7pLH8md~}T1nPh66qL=-#vu@tgxH8pf#+~47Yt_1~ zhFNDyvu7^h`I=UFSvl|ToyTw3C+!wXp3qa2za&q0;@hhhVM@`)w)+k}y?^%D;U686 z%6sZ}nZJ)JQc}|6-)L|@>+kAsZuW0^zt?8JI`eh=?c4kQ=2tOP|E>tA$kVQp%d}TN z`+GFr+NWMd{AURMvL#MYb>ID2|00#HVRRoie{=oGcqTtaVSCpnX{XA0Hrr(<)XjQs z{jMwdmgl#e+3H7Ti}&>2y78-TYo61ISy6Y}rVBl{FkQ>bFv(Mafl*}wQ`6%;ea#iy zj8$hom9VzYaLWnbDJZ&dqi}yQx77C?KaywgPkw&B_eGic)Q{;Frh6vycv>;U^`HOc zB|qo+=L$RDBdbGyH6DLftSoCCFFaQxb9GYQv)wz`UL0cIc%$&!_1Rsgt=6ZnFstOT zcw_Ig;HgcKm{}yt&lj1S&iuZ?pFHc)kJ}Hv&1HJ8BEaOjYlq99xE*UdcA$3F!OyogW1kw7VdZ&E{^OIW7dG+U3*ZM7-GQA#TkxpbwBEh^7=rugQY_iD!;TfDQpn2^t6h+30@bx3J|Sqi@@KXMVDIXFMTsLrgVi@5wtSozs%?Q||j&%;aCXU#BVPQElL3=Nmu6cx+~B z7H&8>V`b3NNBnDfqxCil^PStBQc^g*;`(m(f7)xEH&6Mv{crwu>pr#Fw@x#^=Dm|w zsGFf&Z*F>4zA}^fg!acdt9$n~=O3T5P_^9S$E;^QGCn<4)h0II&E0qIx?NJfR#T_; zRHc+b{PEjOcfEOpoNa{Ik1KQBD2}laa6hAyv`=fl+ONPOsrbl~GIrd|@vpDWoH%#l zzP~ehdJ7pJ@H*XRsC~V9(n)ji*X^v2?-*Tke1Eb#=(*vixM@dtmmK4}dFQ0ed(V5z znq%(Wd&KScciIU=LA6;*+)~wliK&g4^TZqb`)7CE-u*R@S*dl>w!3Mj2TaO^Z#^=5 zZhhxp%i;Jsg_vBB%YPR#XKaoji4O?$%|V*HNChWX1GXM`S7{U zpQ|@PVzcY%pJwT!6<7bc&Zs$a{6fds)Q?UtV~+8cmu(Sp_-jEG0 zoaag2WWil}%l~yvLiWd~)gHypvm9A+1V4w|bNwg&qyBSV@ZVC=vvnSqUfj9x++>1# zaqaO(VxE`g#A^Rdcy{wglK#r3zWL%ucb-$foLf=r+3=_OIq&`b&EKbrUz)Sdob_^E zHNl&e1pd%jXdd|7kJqw>Yf z{>#3#XBgh|zqj>{xcuRSyGcH&Vy?E6cxUq!FPV2xj&V}>r0)}K_#Txkh2~h%a_zGf z-}HBRUt88Tr_41{U+TSS@{B#k8!t89y5I9{l7B||ArCvzPC>!6a{J%QkN#&k(>?#~ z)vy^I9UWaW&)M()$N1-I{@=DkI~OS(`)PX5+5M&du^rE!#wF>9Ws7HBSaDfA|C(Y! zd4`(NyK{%v-Tim9{*}%4_+v|sCK-uoq!s0f7G6Gh`@YEXM_)}II3`P7w>%sdb%}kF z$aIOLHxEBjTAFV<;mo=F`rFGdf0ZjSf7qMt@bL}%Sq z<0Rp;POqSMpTs5q=>m6o=c`BCd9D4V|6%{({|vK>=D%LCE@RP$IraRltE;x@P0n_$ zyYoGlZSRqjHs|yvKAGfqQvLRU4{QzG)9hrAMILNtm+0`975TSBW9K>DFQx15PQJVU zX@2$Ry+7lo{n#dVO(`a1&7NDAJyK>Iov=}6v&Hr;-%nj{-&6J?^PI8+e}d`9Lp$1- z+mhPUd#}uz%J%PjaRLtYQ3@hwrU)%GCrSi>X?_$YmW_Oo~3u$jXTzEbI&W&5|?n~X?efQm?HR~ps zow#vV+4&x4w&$m})i3I<{<ZV)%Tg)bMGVz9lPE(`Lpuw=%5!XuUTat zS$_WSejUr=X@XW_cO-AGojP&n-D74ue79|wZ@bv}LpYm>Y2)H5X6Ka2f7S0M&zbdJ zaq*Ywk7J5Itv3|oHtpV;5t7-x{k6aj>n*~P<>`sn^Zqkr?f)tlz5a1f(nd*c5o1ep zt{pEQynWvl{IP0Qfx^b#>^TqD>t-^advd*jp}7D3e};y7%jo|Mi5u2sbZnfr*K)_cbzjOS?R{hxem45J<&zhTS^M+n z|C(R^mfPWxZ&})#IlE5FT#M*A+|~P_S=6`rl|W6qmqX<@+eHcvy4JJSPCI(@gm2&4 zNy|-dFdAL&E8FF9Ktb+V^Tv0!|GxUYs<+tKbSm-3Gp2L=Z{Mtb_T~1Z`P(#R%kWPS zZ`)x}enP27etM-<*>0cyAj@V8cmH+IKe0_b;TT>JR`R!J-bn^Cv&ql5?CH0~;$pk(n^Or|n9^IwFZo&LGwc>N7Vpj|Qe8m%*##gU> z`0`|{08KX=1u&bG%b(Yj}n z)7MM89iKK+p+~$Heet z;XlK(JIjB)(q>ngZ_g@b-uo-+u1isdY1im&(Dxjd4H_8{;l51 z{|v$v>0j5K|5jDI^s4=%e4c+>Z~i;)zh&3*KfVv=U)ybe^X0ecA^#aV_Za`Wp8ng` z?$WFIAI;n9qu%^yNMC*{Hu#^~hx4yv=fC;-q3ExlFbBWTL#3d556+*uZF{8l*Khlq zuBH28_Uv~*7x3q*S4o~{-^6JTmls}BOmV%t?#jA8Bgg)fdBI$?Iz>v}5QlY{fxlU3#Z~f$ANX70&CvTSBStD>=C^9=nO z)vwK3t~l?=nh&M7rB@!4eeQhvSfl#6Eh&}D^6X3xZ;t89=-K#ag~Yxk}B_T7bh^Y1%4+_l~BF(;t^Kf}o*>t=5KGrP3b_V4|r zdi(w}*cWZ^Jyel$ll_V6BMVMFyI|ut*3z64FA3j?i@m++?a%xBuKZeix_oY@jMC$p z+%qiSrl&t=>7S_ls@?tDRR0%C&*k0gEtq!Y@tv}$$Nd3*Pn>T~oo{)) z%{;irI`4vY#RZk0*ZS(OFE?9e-~!Rc&>^7S8v?;ltVLx$s{k&=QSL1a3 zMUPbYb2ZGiob#=2t@lsf`D<>cXD`{U)AzlgCZ|GSZsvmuhV1xe)uiKU(^~U4r!9=z z_U6Rtx!005#C|yTqPavWN~XGd`^I(mXRZ3m^X;qiGQa-s$5YkZfc zzOj9t{A|~*iSgFy%l9;`7p-49XS$@d;W<8D-8sjcP5c|m*9t$7%?;mG+I-}(-O<(k z-4i3yjJj7Jc>TrIEiC&mcPE?0nf}Uzn|~hOJE>f4@4D_}tzy*Qa_7d!EctcPy0`6L zzg_y5{i}ME)a$p8WJ;U&zxDI?Id!1+(VE!8+kfnLHvC-}e^F2@dB)VcfltIL?z-C) ztciK1b9LHWp0#cACNt^^w*33`{-ONY{`9p*YDOBjMSQX)4oF?wl3~K1zw<|Jcq zrGCJ=kMb*1EZe0l&hVZVyk^Ofx9#APpL{dFE@Nvr5aV1u?J!rp!P>|jFVkD8_=!p8 z?DijyOZOiRnw$1Keu9m<;+(EE({#ets(jpf<;_XXxAKdAD)k;R@?;R7)^GQK$z?v% zljjp3W_oAKPh32y)MDvQo*$=8ANPfulyB{yW!B#Cwx4BgWk}r0!lHl1#eGS+p4HQy z8MXbDX})pnY%Mth{v26uvAicecvtG7 ze|JybU)XU{dUCglSg7fPs}Xl1j_M-9^Nk(o@9-U;J>RVwNW-ey9@O<%;wC>+?KM3zvFV`@< zE`5Dw{v6x$E3Y1_DqS;e$5EAOvG>!$J=fjcx;5*_wfx=Zw`bgV^Xx}YbMD8rpL%xx z-W=F?S2VumSI|$X_WNIdgiZVYFw-~fo44lVwBvijPJR2&a56=ZUH*mE+AlS2XZ3nN z=D7YcUvdBVqX+A=xIo9F()+2$Xmj8eMz8c>*2Z*@3Q6L zN8V1n;Bg}*r)b)Q<2&~rTpq_ME&Vq-Qs1-q&+j?TC-pr~Y%G0|y!qP3DJuQKo6|Hr zGH1MtpS`=``j1t`jm0)g&n+p+o1gBhUH)N0*p|~@7M28_7CEb8=5gnFnaAClInIqY zc)tbx^>|PrSMM$8KH<2^)xwz(MLC^I%1*1~R`Ax}JAALqF6#;dvqJ`J)T=VK^C}O` zKkoQ`>`b>$*b6)7W!tU@nPqq?->90nJ^kISzms(A19m7jy%FlFWa#3&waje;v}!SukFN*yP0pu zf1JDXh)dv|`66$g%kOQ^^ZTd&dcq9fUHaMS9r7$2&t*4Q-MH7c{js}i>WsXG>xYwG zKl*4J@v2wKbmmRo3S$8yi`(BB6fVTp?^rtj$Fo=Ge-`QgZH+otE4rg!VLNZ1_j#-S zd4@I?=BhLM3Q9lySa?HTpGEf*X2H4g4pQq;^Ii1uf;*f0VjkaVnw+2XZiCSg)^`aN zEEbiSER_sDly9cXW*z3M>|J~Djk1)cr*35N&{bapL>Gw~DHtZ|#3o&$NEdxjRoxHd)SQ+h%u0 zVB^-*zAc-MTGy(X>^T;_zJCYbhqvq|qAyRUKEG+_Z@j;Fdi=`%4Su4ZQ?t!BOx-70 z6!Claod;!6_aF3Iz58UhZ_=T2;XMy3T-lw!t_z&E+V|`Pp^GejW@?2DO;OT(9W42~ zqor@XtBW@7d0ocbdHqbx$!j}Xc2{ei*6IEnJIU#UN_uki?d?`>6W_S)$;quwwTcW^ zo_Z>7_RP;5k58S7&s!7zI7L5E>dO}8cY3V8^=#;tInCZFS+jQH9Cs6SsZ%`St|c>^ly;*-`gf*JSW!e3SdVNlD)#p-KGI zkA;2aKL37tM=@4!k-qbO&&##a_6l}SUv!__BM{c&94GOxN61+@BirrV`NkiULY?Q- z*Z*PudFuXe-d5=1^O&37X?=FtzUy_{-R?I@wB1+kZ`)F*GQq5d_st8f`3z@{miNY- zOE#2@*4sH_$IV6JEsytU#xpPJyllI`$wy)9+P6~WFM6k1emm#>WBIKA48N}YXSg34 zw{zbe8L53yYtQs@8$K=6;b}X)_`+nx$o}lZd~>(io>iE1U;X~UD5)i%SN(kT=Xzfe zkG=eSQ&Fw$t8a918yxvI(}%VF^STV>&w1bMi)QXmo^gH6x4p4 zW%dOliQUZ&e|1gf{*ac}IW2o^*LN{3ADx+ev%;6=@7$hqb$#{gystK%8rAb0r!;w} z2=1-8aB1(^XwCGw(PtmsjSKE?+;Kc)v-aZT--pwy56`+THbGY4ukc>$dL{eJ!tC;& zXJn2~+_!n{cgm~tvQLd~ ztp66rFJCy};P$Fzcb=Jje;xH!(Dd>B>hetwWQ>ihmd<&~^fiCgQ|;u}?iv%{ZVr=r zU;U)9!8~@8 zLH5lA|Bav4T$N7TdgFG`QJn`h`CUfGCjT(md8FPmZbkR0tr^;!EP|%<*7QyN^-s8e Pr}kCoC?z$h`u{fp`iY_6 diff --git a/doc/src/Eqs/fix_pimd.tex b/doc/src/Eqs/fix_pimd.tex deleted file mode 100644 index 983fead8e4..0000000000 --- a/doc/src/Eqs/fix_pimd.tex +++ /dev/null @@ -1,17 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - Z = \int d{\bf q} d{\bf p} \cdot \textrm{exp} [ -\beta H_{eff} ] -$$ - -$$ - H_{eff} = \bigg(\sum_{i=1}^P \frac{p_i^2}{2m_i}\bigg) + V_{eff} -$$ - -$$ - V_{eff} = \sum_{i=1}^P \bigg[ \frac{mP}{2\beta^2 \hbar^2} (q_i - q_{i+1})^2 + \frac{1}{P} V(q_i)\bigg] -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_rattle_constraints.jpg b/doc/src/Eqs/fix_rattle_constraints.jpg deleted file mode 100644 index 2ba86095cd3c3682160dedebb745413be563243b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4556 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 P3bGek9e^r^`2RNno;F+a diff --git a/doc/src/Eqs/fix_rattle_rij.tex b/doc/src/Eqs/fix_rattle_rij.tex deleted file mode 100644 index fae0457c60..0000000000 --- a/doc/src/Eqs/fix_rattle_rij.tex +++ /dev/null @@ -1,8 +0,0 @@ -\documentclass[12pt]{article} -\usepackage{amsmath} -\begin{document} -$$ - \mathbf r^{n+1}_{ij} = \mathbf r^n_j - \mathbf r^n_i -$$ -\end{document} - diff --git a/doc/src/Eqs/fix_rhok.jpg b/doc/src/Eqs/fix_rhok.jpg deleted file mode 100644 index 829a866be449ecb0f23dc77f547c5b7d053c0469..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18330 zcmex=5K!Db3KSa{e;dQH-a;{TE#UDYWofz;ZAV#De1k-i}u8 zqMx%E82E)JOl0_A=b^l1Cc__PPA7%wmgj;zB!8AE@lAd)4W_|KIDvtIfw|*fp#3`k z#dBUL^d}#9YR{Q8FC&3zh2PALOJx^)&|tS*F8Ofbl%jVPGAx-E327%H`7b~X&|ue8 zsF?nNW3eskg^dkdimv7X&NELYX}FzAQ@6CrY*qN9-g9P}ZTG|n> zlUP}<|Fob*(HCSn$Rx&|X^R^+O-q18FT;87Miu_1CO?7Wni0CkCoX2-x$>TM%>)*~ zFI7{U=j@!AI^&r4$y^QAKa0dSfV49(Ft7$}ojFk<-hqLEan=OahCXezKMXcrhV{zl zCxH?yv$ej965_qa+e#=BW5xQ*JzOnQdw|*!m5U6%~g=NV!x5X2mJ&F#skh%K7I3J;OZ31aKO%EniSi>z`&ERV|oIg z(gw~?A5*F#o)Bx%&dUU^r{TRE9HW4UTp16swu&zOhu{bYZYQ zn_S$v6et>sD=8bB|G&k+!N|zK$jbEZ?R4p9I@6AE|7ZBnCjZy_wa=Q@!lxuR%8Ti) z+GhOJbDvVr<dntYx-uz8mqJ4?Mv$~ zmIg$H?~vG5RISn;6%z zlGnAnzpPz2-D}C>n5(9hTpj_8A&Cs#Z;i4|9qdn4%W7Y|HFK(w)&BTk3xP<}S9*0z zb3`5sZtC}(P!_pU`qJOtuqXGd`NA?{uU9?#7a38qgq!VXbnn5ttyR1>8n&;e=W@yi zXN!H?d*q1V;ZJqvx4&NJtlD%V)BkuU*G}Oz|0c};&)^z*@JEJ>%c<8tjQ@VToX_OR z(P8{(%|D)`hKTobO>g^_9-H;&kynd`ZA^dXnnoMtXHq5H?O!+LRoyhV&6(XD-*nG^ z;kOx=4#%Cc_1U2FBGX{o;rPseB6=7RN_t*y=1LNzM=7{cVz64MdwQOf5N&72Q?$Ij(Ep)%>@JNlDG@%;JD;+qSu$=F<*v zni9LR>^7UB(Vyfu$KU3iT^2U)B*O`fELAhEg{(Jh&R6^JZ?I$HtKhJh9I&PNX3=Wr z9RHinY({I}6~#T!Sm5DP8ntNBl!w!PF4`Hjqcrid;^iyX=I-*nRsZ>xUH$dI`g4o^ zGjw~{^oW_y+WKvR-^b7iq9W;NKB|-K564`rS+o1dJapF1SZB1zi7BA$RKi)LDB<583BP$?zsVZ4EoWCUnvHTl!Or zw;zsfRNb^@g8omjohN?>t#w}2J@5Nz{!OuE_f)oK1{*$naO8~XFJX!Mx?g%`_G$cL zGtu65ck$LsCfzSvR&kuPwOc>aVRcMKr_Zde9Rc;tH)M|OQQXp}_@ANqZoMS?hnmOl z6H{|Ut?L~(bk6&9gLRYF23_?Y{|DC=&)|6fbVvH4)Kx4~0+V!SXK0({ZCBshxN$Ap zHl0OkZ#j3K5YrVo`1M=m;h86La`-ZnS!*pY+pm~PxIfsoI%lOxCJ|}a|Wm~3a z>HCD7Y{#|T8lAhH@`_lyT@7lhm(JIe{WFQ{Lf^&Z6R)kQKBJuI{*_baE2m6c-gEc+ zxwns}@7poiWu?<U>~VElb8gY*T_=Cs{F(b>>-}5v z_DE?8AKd)icT-N!$v$a_7twzt`%I)1PjCbiMB1g~GX6yK;NK{^XdRaW^;j%yaek z#w;oIJCmN@*;rV|cck{)oC^IN$1Y4gnU&*cX~gtv?WtM$v#!1V$aZ&OdQq55O~66Z zNfG=!J=2utci25m&#`>VbTFwkZ?^A-iqOngKT>{(vJ}2unDb0)qqfF2)t|4EjBC78 zU$%vX{AchCdKGcBZV&fg&%4e%W)aID@$Zbh%~$QPA!1?lVza92)BS#Fl+XR3Z2tJR z)6FxXNnwFG-k+}>N&7MF^ktqkEB{Seda3=T=CX}v45QL5FZv&mFWS6K=38UJMyKu0 z>Qg;jJ{|OOrXQ0p5lT1>9R059s}7 zXL~9l!|rzY4AU0F8%O?b{HtiCdNX9fhU0efUMdf+UUl?)6t??)w9JHQ)_lrapM5R4 z^iC-Bb;<<`Wp#%KJ(HRnZhXHSSt6o%{YaT7)0QK1wO>rsJGGRx&GN&qKy|ittGKEs z%r@{c*}Y@WJQ-ILT>4u)!ur3@eUUv)R@Dp5`qw(;hip$z5}R1M-G19OS(C|6d|6Un zeqPcaxtMF8g!NgLl$UR8V|dJ2Yq%Hv40e>Xs$SIYQTSII)F%@}?~`o+*U!w1jP{Ju z`gl|@!BvC_FfcJPF|n|7a`1Aof!Y9!Ow25T3_`5JiiRReMvj4rjcfu6PCo-tJiLOM8}CTn?N5IrqhL`$jA6-_5`M@9&LG4QJ1v)|-4gCp%GP z>Dw}=eRm2RL%;dG4O_dp+V<_7d#Ch|ire)BWQs1lq}HVs*7@{-(VOJDob88BH6Ge- z(h=~B?~d_yRoAnv9}@c3+dQtx7Jeo>?eJO6(^5QVa%*SUuq|$hh?yFk@5j7B@7+!1 z-b%mY1rn>)R(zJKhzgdlexslLP`)g&o@w2NWgCKzTzay1ePVSYNTgzF(TwG-o4mR6 zgTKfncVw0p>#{A`?JxZF@%>4aepV>EaubZG&oGSCCs@;zJ zpu$AQQ@LlV_^W;Di>H6%Q~23@^I_J~xh~Vr1mr4|%+8aosP#Fi=bU!p`o?3OYo(P} z+py*BeJj82Kf~OPhtrl>Xr({NW>jRK;_z!u$iYR+OqWDO&DzFdeB!RTtozyTlXr1l zKDoG8Q~3M8lV2W1J~8Vv)jPf-X=bX}%;}LDKXZ@eN7}J8ty*yD;AWH6hF!O77Vefm zC%ONa{Ev@+9?t%g_@AMl|G?^~oyNIktBh}aiJAOBoqbW(>Gxc(wtad0$Z~%~_shdv zy>ed?cw3i*?O*WNGvwZx4O4?Z^&Na|v3%j$>dwq}E6m-ZbAR2=lXnk!v-aX7sZ8+| zMRk4WzL&Io+CODZS!#4L#OI1Xn{RfVwbhrn;&CxJ{z#*5>z-%dkC(1zU=#SL)ReQ# zHCjIHj?cw_i(7V9EYg~$TbKLswv=}(OVm6@wGD20J2y$+7N|M+=CG-bcA&XQzM4aI zPT@yY^Vk0w-adZhm4E#|!|g++KHC14Pu=?G@ZIJKyB=+}Na;Yyyd2fi=(JU<;>3fE z^UZI+5m{o?yyVvR$&@qB(vHk)tE1DkF3aBUiBNl+UBX9o!y<=besM9 zdXek^Wj{_Y&56l5*YD2UUi?(zLX~aV(-jXlmFiUQKjVJia?!=p(pM(!@$?sMODw2) zEUF#1a>C`g1u_$l-tMxk{U#>(?34cHgKZfRu8}@B9~SRk>mPWuR4X-dmF7Le;tht; zNnMjXw-z2YDLTP)KSKQI`%JElr~AaTKkwXIvE<^^gIX(|FHHLNc5Pk`Yk;WR0rve{t_m#?Sg++Nt<`s@rqJ=% zsalIQZPQXFuAFyVxs8Y8#-aPM^L|~va!RqYd~@x@rf!)G)+#yXMEqGux{?mslqEdT)HeEb>)Xu;HvkZKQSB z-yfOVFTFVJuOD-Kf;H>yEs0B~Jru8Y|mAw`3=2u!w$n;2o*AOkZQA^3~o_ zm036TtXaYz|E0`RE6{7sy2=S(4DVRiev8U#5pvdgnricyfAOoEvz@QbUei9K*nCc& z{jUQGcVv&0Z#uDa+QZ$BJKlQ=dqsJCJE7!OGvDfPdY;(ERf|M=cjep(zTFu$X_M5{ z?(7-2eio{;UlQE+(D({MC`K`X}1VCj4yJr}=8t9F?hkSM~gR&XrZI z?adM56nawG?_RrPYLn7?b>47QS&{cTJ)Bq4%IYPeuJ6+{nQCflw#cyJlEi_a?@#4s zmz1wC+4aU`@+z;Y#3Ir5H}lSY)$5M^`kCYYN9SJk715t|-+VYR)qCPh-s5pv+N!rU z>VE2dQ`w$*;GuN3da|u^eZ=j*(z^|9or{v3o^MEYy0-0vNsH5@wL7=&3tx7xxsQ8) ztH%bxOG`fPKRsJa{$f**S=6nQLDQHooIU?ypGgY`L#t+#;q18`ThGUyGl@>^e6_=- z@`uk-cJ*b)^E9SeS=mN=SH@~dHu%-Pu;FA4bzIt?sH@?`Zey}QS(-nOw&YEez3_};cUYN5*C@U!WwcokFr9MfY zoS9E7UZeZbQ|Z#{c{P_k4X4E3*tpZ;lBR{r@@XrVHJN5V3A<-&QOEI8toM?;Nki|H zq8Q%vvvzk>ZM9fBt1N$=vtBh>;ab6hox9fdJ=fO!vFVy|&^h+I!l~<@?bBquW0F1f z^K16%M^WI4<@k{)_t*bt*xqT8D-%-o{ltD<`;dNro^`l(h>du#2S`2u7_;Z>JH+Q)G+gG=SD@vo(fGJw{l9go6^xE8dl)?@Nv!PDgne83k`wB`-|YIUsTI3rsn4a{Pn=u# zMs)S{>H6B#OxgRkf{~5n0Ni8ohz)w4C`%#ysN%r${F4Zq6 zlaW}uv*$g-t-leMYR{hB#BQV4_s{d5-ClN)E6Ta1ysK7O-G7(;Ht*oQWy}6Eyz%S2 zVe$4=aM!L9@wsf<{J&M&=9Y*OCJO6JSQ|Mf4-$h_$scB8Ho`>)Rz zaF5$~aPgx;<>1B7jScQdr>oy?S#)Zd*R76~i+4PkR5t(YKFt@(yzjbhEo1IDSbqEE z-3Owje9LFHe*6$o?`8-lG8RW1cj~UNKe5ZmY4XIXRZIUfJa+$+KKpXV%FM-A4@+$7 z`xz!VrCXrjO2}%_w0@o_o=+(i>++|(F_*2F=CM`y+NtX&b$T|sS+O1d&oFOI`0-`R zOIEF3r8_(9?8Iw#LT{Nx|7WoNC@MBF%WH=6jmhrD>7mcWw6|aGdlknpX*n0;qT=bZ zD=fObGnFMwPK8aIraVLS`$n7RQv9BI-NqMB)m1#IpHcNk)>tpa@TJo9`R1|$x?PQz zd)bwyL`i8%WeU&Px?|c=xoOJ8av^r2n zrz7SDlbgni*1komPVSc5E;n4Zi^_QSN!|F(^H)b@Cf)m-HZ|nOsxw~wt{d69(~EaLR+9bN6oQskBiK2v~`Q47F4Xxy*KIp z#V>7BGq?5!bxNtlZ(a2}uk8DlSe=Qd4mx`8bS1B!AQ*9$2QX4&SPq-t(|^$`2lf1v8HsyXNKHl3>svw4;ueQg`jspu%< zwLpn6o3H;suk>QJd$JK-kAH1_y#38TmS{ldx53VXGM5d`SD}Usa*dd8X>-g_CpJ{x-I@eoI>IoXHWytIYJ8vE%oglb7uJ zD^{$Uo>H)I;%-BBjvqeLXJ!A)DHeRaO=w-)YL)d$hbBl|ZQgkF)$88qskcnC7Ra4v z%YX8Hc@xK+<7?;g%)F6*Ln0zRO>2wUgjR)126`JL`gfk0t4y*}-ydq3$Gk*h#r`|X z@4v|1yLkP*nfG(5j3#TXxaG5{nE&Lle#0ZZzRKpD;$p3pyKem4R>7-vP}Q4%r*qEn zOAg16So#0!|9hs!dC7l<7ylXV95%jqB~T!D+G5@F&n7=8w|0GWI(lv1-l%EcZnOG5 z(kaM%+1WRfbHdEHZ!eF{eK*Y|<7L+Q9Xxx|dTX*vZzRn*_C>@ySj}VQ6Swl%mXEz} zcgWsY>A1wCK)`#Idh@n>8n(6-YuB`_U2)6gMDW{l9y>lqw!H~`X`6M)#$d}yp8&Im zHS4NsuDv~~8tEH3Ph`5f>(Sr8tX+Gr8fUBi38_hbY3ZI{y>qYlUZvznjn75(DZgs8 zjxXio4cYb5*!0`iq|Ls^KX66tPzkC(n=jF~a68+o?xw&?;vubCg0mux%>w)@$ff9x?4F$4=6~kLX==_&jl9WyHlXt;V{SF`HTU%*UyGtTeGisKZ)uT^i7)u| z^R?+u?@L!tdarRzREU?}zj#Z;-C(m#@kiZ{*-f5O_I>y4i`AFZOegi5tAF!ferQcq zz=Nya>n0n==Z9&V+^J_++TG-;{^#1qj#ttJSu1v^$|{z61TB%0h-Rj!>9~~}u zwmegRbMs23yUP!}OIz_NZ0*AR(F>XPe7R~BG|yI+JMytn?ux`Sb?)2G?(;CI*?7f~ zC1LmR9YSUNfk$5KPPjNB#lCm)i@?{%X2#3us#*!&-Yk3W#lkJV;fGY@l?-cwGIqR^ z_6$|EHg|fTpQdGW%+=QLs#@&M?>Vx2;_Xxxn&@23_CM6L_?e{H`&*N!g-c$4Ut+eX{ZrY_KacZIyf1fL;&@h8YpqQB?bq>fV$&oiZkg-Nv7kkI z&hfM)E4Dwbp1zVRCMy44e1pL(*S2E8G%3j+x^dawPg13eOSs?M-!4)RdQNfL+D}d# zHpyR=_o{VI_HuUT%2`#LI_Ez_*#13#UCnwg3LP|3Nu8N^SBjfIQ{v(+Q?sR3raAu^ zHZ@<$zuEUv^Squ}L*td?W0R&)_rNa67bLOy8WEopR(^> zm~>b!UK+Z%=XY)P>qD0g8<|aBnJ6OATs-5=8Fz>Ky&dUS98xUr-Eon5zFbPv)Gyw{ zbYkU|)H9x+lX%5d9%e81`FJ#WOXY9=DqnH6DQ$fsH$#4%w*0rYzVcUBuJj_+rWB9U zMu&Hqh{;_tT)ZVK*Q+G!=6{A%_9gc>%U%ke7n94#yyAGTs@A77RZF*f7uMIA>E7z< zFZX8sRk(PC*YkNEz9H}HJd`^+fsh} ztDLhm>eaL7pELW@_q{~QMdsqARTq!d?%VqHVP@h?Y0oPgx;Pwno+(RHUXXvp)7R5% z!jveJ-iVkt_s*2(9j@)xwOgMu>vT@NN_3q`S6@ii#uYDh4kQYn46uEwu)I^T)zWam z28ldge;LW`uddzuu41^st5qpN=Eo+@T@O<|ZRj#ZVw%&WyHc4ZGRzc_?IyN0y-1nwG)_3(i2HGYg(E z9(_|)_@9AyXGQGYpQn_+mrsR6*mc;ziw=Zu`{TLYX@5M*=!p+m} z9NzM1+RVO8!P<*^mRm>s@;unKjN_G(_2a3|`U@UEs^Y&I{Nm7A|HT>)W>y-xGp**k zowRJ$q^UkZ!MC(}zMWQl`HES}uII8;#>)kqYDJuB+fDoD+!y(1YIRm~LTZ`!tK&WS zXE%Q@pLyRUVDrYE$v)HV)<|kdZ9V+rO-UahTSl?>q% z^d%eaZfDd|@|<9hvrbRXJaOU`D}#+;cigxR3OUUA>AG==rjTx~+qAVMUQ*Pn0rxJ`IPtc<1|uoS=M z`Ru2%hjA>n3BOibQk>%gi!MMJ#Ha08hx{#k!5Zs;acIPMk~fUiH)WjJ2O;=8R_(#qUa=D&E?^WR65u zLf<0geU>3czxeFb7yJ#i>(ROL%czfY`ec;?tqpItnU(~k_uX7#^)}l6gmZ5D`t%Dv zU$hq|GU$ZdY&LjpcJpSJmFaC?w@1sC{MqGa}!fulEfC8{^0c_foG2tKe@lZ-?M4aiS4{;;!qL+!uTblRDd;1&P{~uw{5nyCsWCj6N z&>}Ae1_nk!21P^1z(j$OSvacTeny>-_d{C^*q7pc07MqU#i!=`6Xf> zr~aLE;X!fvlPcv!iL1BAOCP@$v4BT!OUMo-lRQ42n12DEe!ApbkUNmHE<8c~S@VB} zju?adCe?3FFU{L$$yBUiikh-4SN4nL8SjZ(#oJyO zuPK$WIBy!xcIfSkJm3A*MKvYPc3s|o*N4O((*9Mn#M9m7&$G#slN7kuzCIv*=JeKi z-4mayr+ZxNj^KWu>g~@KkmHz_oaKC9QtXFe^~9|nd7g7OF`h0nUv~Y{hg81F@w0Eb zZ9leCf5~>)v{?xkSKW4fy4Xvd%m0X3WzzcS$|c7tS|yaa656URR6D;9kbidm{F`f& zv*&wCGwxXW^-_EI&3#iP827$(N_?4mK9Ilb&-Y*J&)2W2I(N!opDo*sOG_97R<_Q2 zBy!v=K+R;4%er@#u5IGKSyd9=w3xK~Soo~yW0Q%QpK1BL&S&f{c8~O?OJ6ya!0n8 z=RZ{Y?$^jMJh398F6V9D;aasFYz89v${*|5rEfFbZ87wbN=ZF-(S1pR0&oBN`nuL) z@i4tF3RV`!Cb~|z^DsV)d+MnOzR(1oUo0GgEbj~4O!lWlIr^t60&W3DciK6MtSQC-d>G~Rvd;hB}^5LFDk;0)?T;KxXf_O^C-iOrW5IgH@~eFdA-$D zD#WJ7*SJNsY*Buq;D+jTPg67|+|}=ww3{~RyAzku(dqk=Jys`uKdQeq-6cZdz^O%t z)*tbTWD_wLy!iUBuBTku#h^uQOy-7p9&=xEPhIuFdxgsy<8_)#QrMQnPTzUy+O&pC zFQ4C9!NAD4G$DMt!GXysUMix$9c&iJY*lKOj&9!C-soV{FV*p%A>@hUvOvZ11yh+y zUc~2CEKq3JAiwO%#`TYHh*zwwS3j}t(aiF!`+^r$PSi@}2XYCh^xj#d^hwHpA!Y`D zxsPkZ_n(RX86JjbB%RDuxprrk;`T`Cu&jmORx>?eJ7;{za?dc4G@3OM2f9F^H5d2l5bMBDp$@vK{JXUtyaDH80I6JKS?|wmt30BIR zU+%v3vB~v^X>^s!>WyiA%O5l^V|TP#^waTk#O#NDCm$VViu|&?RgtqK@vLH#*@J}~ zeo?s>-yM9+xyeeIc)im<(J}gKJVic^71-m z))B2L%XCceSJ?ocb594P`+{Hqq~ny|JB+*zbsp@=R&(&r&w~^0ru{B z8t&8Cc~d;SxtA71Ej-J4;qPk&<9S;4r@P~3OjxqnvpBM9;&NS!+jlY!v7WPB6Ja#- zjH_-7n}LyNTS4rkJs+5EA3pN+s-k>SobCNfmmh30-P69}&{ehc4|*3nrQ_h*@QPC*9$$YMhmDW69o3*Nz$;D*icdJ(u z`Zwy!y?>ecAyVp|^OeM`$;Lm#GmiAGw^tOlx;1CH=L${*fo8=S2Ny4%T43qDM@uez zkEa^bp_$vcy4H$&wkutn7*@dS8*106B<1mYZmEa+jp_a6U$*?v>CIPs5#>CWv)X@e zY=PsKPT>|67t6L%t((hug?VGdy&gZ^#VBGn)4FDgK1WfQ6z7uN0kO&!I?0jE zVrf!IQ_R(ZGz2;Id<3he@6bBDBI>*Buli|ExN0i&bxj^jDoVQkGt_*CYGU~`n+(}Q z)C7e)41OD(PlBD;w2%>LjDeanXWU z?fz*mSORXPy!{lgNAYAthT5dJVeLr^gbtnBAho`11LHFx+m`sfx?7B{S}Qk|y!;nE zLG$B-JzFj}d7kW!e;RV{!PM4!5g!+nbG-HLH-7JR$v)IVdCs1|Ngo~lGeo~zUU8{s zo~z?uk!O>bPW7-Pwj_PicRkx=E;V^AR*whnVqlTv;W&BvUQ-(Pv+PYCuX@Cc6{h>` zWIR7>UvcFd_Y0niJKgUtF!Z^hy@^A8n(oruMSqQW{zkC9Rk6`^5>mQ(BgX8xMU@hZ z7U$+d19knqE~&+V?#fvW>1P)AxpjEWz1nyosYf@5v2pWRbsny!j`mE$qghM;xEcwy zFSr#n?Z*ejG=``Arj=U%8CLjw_VR8umAJ6tb+nVnGaZ#+o!>l@q9-vY#&3G(s@bF- zl@holwPW^M!HJ@C1bpM#8{1uq)|!5;I?&3xCP3e48N;q47sOVyF}&(xS>xubCF?e? zfoDpJuh+?WO=3!an;*@(BKStYbD7emOS=s&9p71dYR}aAD{7TXRS(VT$p|T3yO66` zOi0^I(&B4Vn8-_m10r|Y&YbEBrqGPrQ_nDOqdK*nx zS1C4FEo#&job1&exO@S#s-$qx^d>GAF@3fMZ=dE5GrtQ>i;z>|;<>Po^*Qs|IIsP$ zgl#TOdg$wBqGfgMLaSvrr$|a;xAqg2?$s=9kqf;(PEiZGa*O5Rv=8bWU!Ctvb89>N zg@b)*W`X3bT$MyySAu zZQ+?z-qhQ6(&y= zEK(2~A~aPH zXh11U01G1fQ2@95k(H6arn-UPWFzDW@?Dds$^5|hyVs!OGXe^Ug$9ii9Rd;x7H<3qADa>Q z&rr67KWJ;_6pa*trTnF5g3MAGO`=unFEmcgbYftbe7xoC-9FXTT_Q|J+s?K;uPWRr z#c_r8UQk8e%^x?MJRhtGOLkc9u#QQWqfuzOlKrpAi*kyVy?fnI_$~W@&<2s_1>uW@ z?pV7!hbKI-G<{ZH!D4#}7mJW=^VFxaiefLPZP60#n8>4`y({c;aMOZ)aS|=Z zW^ds6&#>?GsTgNnez#+BGET|9H`wa$SEubfl9C|MA`~mYkl`Z}P}~&Ka3@sniknxk zMTd_`rSB2uzY}J&p1T@ZQRjX!>{%kW`J?i~Uw=AiHRQ%^xY*v1wU$M={>i}?t+Mu~ zCbF}b7pZywZCKveAjjh}MLhWE$N9}?zFJNEB3PDmDn(42&p0!-!0^O&6~6O_N|j`v ztu8X!@zSJxxg0OYrS4)6z6TXPN!KoC8y{NV@FDTHLCgiOt89h~(j``A_2!*w@?bpv z%|L(B+IN5UcYi*u|N2ez51EP_cBj3~511MYeI9V%Futl4uB8_-%OWL}_vZe@cMB~V zMNPxE%>LpfILBy-!y)N4#&c>p4&7h+Z{rzdOT*p%A8nkDY@4M}%TQPT{$jA0xWfG( z``Uetw<^f=xlFyh z?6QLQ#r=&h91gICRxs~b=9b$ja#UftAKPyMk40(|t&bkm_UtlVEL9`MXzaap+OxJr zg>eP`|Af4C?z}i_9lpp$5?6O}XiX70urq}#v7t;!`SUxEV;?+xozE!Vnem??oKfIK>L!+zlW#D0%d@Cx zaAxy;arhR#`NH)nHTHLYil6hJ!p+gj_G#wakDPu|oQ4W7PjmTeFz!8Ut02Xn{c7da zR_R>hWE)T4#S0!>VU;nrI;T|VsJ-n}*16L!?;j}HR=?rj=kwQ>ui4VGE2t?>Z}OKe z4lW5Pe24}0S&|4%fxJ}Hx#&{wN%Y{FN4st?| zJzZTkKAM02`<2Q2+jqZ|WqY;k5Xb5zDohT>YmUsi5hJlye*Kre55`+2>Yb3jWqP>v zu%>zN5gA7h2NsTH5|b3d4s37y$J1JDynO1e>O$M(i*qk9Kl<0S++tUyM9g0u+4|=1 z!I>YkoZiVk>i_svC7fl}4Av%zB!&!Thq@xG1PO{dA^nSWr3UYQoTfHCxAuj}1MB~$0hGQVNC$snQ1v_RD1XTh$h zcXv0xWQgzS3|{8K9k4{Q@SDZMEQYuT1quvuM-qgW8dlr=;xGyA-DztGd{OVXUq>=2u|eEs_+%lx0Md}v|mDwZLfsLpKp;8^lc8ODQ~AA8Bz zoebH0r0-`lLj%KwCOsYBi=Y2m%g$Lbq46Szq2;-Hh4lXnTLf+TlX4uD5`;Xq_7uA{ zcyXk%XF?L_m*B-pZY3Q(e&-!mOz9Sh%=sn#xI%mCoCAz5$-5hNq;a%K0I_!|LW(O z$f9-6|4fqCl;AThVOrm~=|}V)qXN?s{ns1J-kTsLxZ~x$#X78ojTzr`FHGT82wxa$ za>ZzQsYJAJREbta?!}LDqz~5^F=zzbmh^0Kf5*UB;LR3Yr4+u=^0#%^gX0b|O|}d= zPq`DVzR9l$u=Xme@F{he`EbI&_KzKk92cAZer<5jUOwCYZ(Q7+)5T>!M9S8w9T8a} zcJReJh2qF-LYK@x?0>Hxo0XwjB^u<)!+nUClj&y!Lx$0h<6e#%Un+Dk$1GpICUwDu z#nazDy%5ck;kt+Ij*~JE+wPWCI)>Sc6M0-ic8O@MEy|GI;;taNg?aKG*Tnvd`yV9A zGTSKa|9XCtp+L=!o7Vi6RT}1It6Co|5$hBcYOQ*bK7;w~?t{l!sw-*_#Q*wLHsSQ4 z`Mkg0OE~6~F7Lhd!GUSHo53rc5C0kb_#Zn>tPt76)W*szUBM%?d25qOuwiPiD1S}` z?}iv_W>!XP2Ij=2rEl6?W(s??l<~j5o_01o)x@jeUhnU+CvJY6N4bi*7VydD=iIkx z>N4wk`-L%tU(Y{fmWksNS2YcR)*oUz9BxK3``;aO3aS<@x!B=!E-<0#lV8@$_QRf6 zMY*Irt}8$EpM9Zd&m#7u!zy}m)ym}z?nyiz>4{f0A7_7l@~vx&y#2IFVMU#oLm{53 z%NKnOl1U74zbbO@=rpB}8LwBZJ6?SIZ07Y9zZbDwVO3R@ZQ~LNXJ_nax$LCow)?K$ zgN=<7AM|KlZ+32ITyToVd{aPO#2>z3D^7QfzsnfjIx`DO>|RrI=#SoBfn#i*%ebbp zA1+Y(?r14~IKBJ*g%tf4Pu3=r*nYuqWz%SxN)J{JiQbcpbLKp>&|$dPDbB_z9`98@si*f? z*ea!L1*cacwLM35+=biP3@;n`96f3wA-GgxU$4xI?MHHZ*bdA#oFDbEk30u>a&{{xpHrCrxL(G~xfE;JeXXS1KbYW6y%WXPwt>;j(?fAsp3{ z()hJ?&3}e=_8$f}Z|-wsS#g=$^QV=jY3;}2KRpaVeCu?k&YZn4^r89MJCQ%yn!L0X zT;yI&IAD5IbG1u+ZPFgu^@*QO$gXVK{8p}RT)-% z`cLkqX6#WoYr6GZOvuEi3%0OaKfj9W{;gxx?hBniirxM<_mlZ`rw}gx>nEb-d6_d# zi%&nF@5FkQZRLei2fz5t;%`lO@N=SBuWb37kOt1xub8TvOV8S*2||2a z4j!Vp@ip@6<1bGrGrv*i@BMDV-By17lfRoLd}|8fPoH@2n$XD`Dw)gQ@kHq)Ch{4m z1iaGSwxfLAjEl?*{d<&l?2{^RYhUW#>|8C=x%|>4A4P{Kx1zTTE~KhRRMpLC-nj4Z zr>gjpwl^9Tb^dom+P4TTsJ7|*wqcszL1kb2f~1Sd+#H3CO6`HUTMzFoIo2V|Rg)-s z^uy&Q6I(4CDd`(eeC?)9O5|d?WIR2Wtyxpy@Z~R0WP88KPrmefiFu;);ZJo(bNC|W zu)naIrufx=qUL{w{f&un2G#4I8(*3t(NwYV%3P)evo$AXuJ~rWcPX#g>_xoi_PTN@ zhcC%A5xRP#W!_PvuLW#%H-8r<&RO}FVZwvkmO35vpY<28YqU#bJUOo5d}#iI+2@=m z`yN>RF`?r2v9LStH$UiY{`7Lz&h^#Tel}XmC@Y>@K0o7N*_N5r8cl-Jul_#4nDmUR zQ1rP*NniObc9HIv_RDk(mIZY8=J)E&t+}HxDQALcrh{N}uwZgp*ZN%?E^AoN`aJ#J zU@Y*W?3h$fhr*NqiB%%+FYfGHH#y66S(EDXhq-&tO;KQIkTaO{NIk`T?&a#DnYz}u z{xLp2QhDC;@f715MIOxaolb3Dwfa+0@S$f1m?rFcc;zOqN^uWEW>e#WJe|IW#Vo!H zuY1n@)_7Fum;cLd9?dCAkE0)ZFON6pP?@d58Wq5jaOL#%oY5)gt_#ua;?gr-y);`Km7x?@CwBYJOD6^n#>bp`N@dQKcg?qJPP)8z{R250 z_c@>ESvuRct29`C(OGS^YQMU;VsT=#+s9qKF$`bUs7OR!I1a9y%9=mvqK@_zhJbXDV;fcHOI?u>VVm_^ zB0cL#dxu@X`ky}-8=RCf4Yyfdn#95yTC?hLzW3FJwkB4_g`V3#UUgj+SEt9C?iFvc zS-gIpGn~U~)mS97;79J4kV88zD!dTksq53oGkB>I=Q%;w=GC1|O6^QqOGNt4X7efj zP4xJ%^3bGER+A6QRAS!QuKVQ5#9mP<+n>$+oH^h!pMu!oSZfuoyemf)8@{cGTD9tJ zOnmq*#bA?(sr-^j#!q5pMVgPEx?|Gdrm>8B4g01yjE)L|hvSvJTuqufUdmit{7Qq% ziXo0cfM;vS-n={9my8-Be<+IbeBL=dq8bK9*1qP1#x3WSoB;n)oodRb>@d z=0hLtGtq$@&T0xhqQ_6DDZSG9aUf)Yk0;N1kwA~K?M;s+9HvDYbG*8MwStOYC8uQIEh6NKi9H-EL$Cz{kC;Z6uXx^AU5pU2K$)32v-_XpEIakr&TI!=K$5sOohh5R!AO5Z>*#6}- zm&EA}=UkZHF&?NBmfOH`&erBj`}*@|7T#sD6Z8o_TC~?$_NMEi*28eQthH0wrZ#TL nxvt`P%-LvX&b0%J4sbBkDZ>?1e7WuFA+s>_*8Z3I|8D{SZfTP4 diff --git a/doc/src/Eqs/fix_rhok.tex b/doc/src/Eqs/fix_rhok.tex deleted file mode 100644 index a468dfedc9..0000000000 --- a/doc/src/Eqs/fix_rhok.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - U &=& \frac{1}{2} K (|\rho_{\vec{k}}| - a)^2 \\ - \rho_{\vec{k}} &=& \sum_j^N \exp(-i\vec{k} \cdot \vec{r}_j )/\sqrt{N} \\ - \vec{k} &=& (2\pi n_x /L_x , 2\pi n_y /L_y , 2\pi n_z/L_z ) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_rx.jpg b/doc/src/Eqs/fix_rx.jpg deleted file mode 100644 index d63b983230c0c26a7bf9c50b38593bdd65196a35..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2427 zcmex=pQIfdgcOJ;VLuhaZ0UQDZ01-+uVvC#9lGbFQ8}p`kv%^sQ98*VX5*PR+_@T_hBl z_WFFL=5e;x?Mj9p)0W#5UOJu`{&?l>?Rl1~v(EcJy}c^&EAutq<4>2W&f08{aBKde z@)&*LpcThHtXc45zVGbp@b$|~dn?Y(y5qK1JmLsz27jaE6p53fthxn%e|hOPZ#P}} z-8go$xPOw>nFn`fEIFgO?wtN#adx{0Z>Pv7T#T3OOW}GX9Fn4-c>9v=CYJ?%=jMuU zKKP64k#)Rx`@&}X9+$;;YaV<0T$`F$=BRBrb>}(rwO@9pSRN3wl5r}qYPn-|V4C3~ zp3oV_Stk#C`kdBc7&)muyCh|^Q`NTRQJTMI9=d*o;ds~2Q`1vI`Jc|Ro3(Re|K$^R zEcBRfh5Hn<{vrX=+ z|D*nu)$S|)&DH&PRkP@#p12)@BDjQ-z0=3Z7x3R z+3v%?@29guP)GQJlKHNSvJ0zp-)IC+=r-09ea2?(Cfd33{_Y3XM)O@$%McLNg<_ia694l>8zh9q!>)M`&Os#MBZ_A!%r6-~x@L|8# zTDf;WUeDg1m3i{?mY-9EW21Sw&pw^bBGC7>bN2~}Z?7kFC!XBD$8Cj9fk>}Nu2aMp zv5dpFT{b)ox=k-vTo%bY`{KC6Wfbk7NA*`IgfT-O^t6AwSXO}wqIYc~IWd}Wqj zv*%T3xo`J3?yB(Tz4rO>U(KjY^#^y-acKr4{6(p*v(xgVtE)fEFT9W)AkOS* zX?6S2cBjDp)z@d0t~&VbKf@WDZ*MtY>E8G6M*L@(Gk3|$-*W#M4!=EqE+FsEw5wJ3->C2It#cOe zu=lzDc>Zgy)O|0tF8s~-#&%4e2@zTckYneTh&mO*e#j|_Ku?_p3C(JZkdUx_Brke`qo>twFvGH{? zJM*Q(S$MPB>_tjz_cg9!2{6iEk;e4OGEG?`{p$3q3#*uTyccU2HcKR(Dx31!Nnb!j zVehGspXKd479BfsQTJe=S@qYhC0CT2mTaC^Ho5NCiz?ZD9{W|@U%r2oGoOK9cHZB# zrfGNIxb2qS{4;TH#p8KfPaN!hzT?B}xt5QYt~z|abdulatCrDAqpS25EUSB9#2$Lx z_kKiD@7}DB19j)f0}LQ>k^(sEisayI=Nm>U#>W6f_ZQb!p-usoXD`VcoyGy6AFaFA2y0>!9r->6%iWgQW znyh)xekNr1w#^}XcHT_M&StRUY+$~ubLdLKw27CuFR0*gYkcXwZF@~C+DJ6|VfL)S08dH+67?N?%6)t#%vy0wI*I_w00 zMxctn)};OZy_V6w=XlT)QHtFFzOd+OQqEQ$5kB(zzk9Z!6ex8dlu;}uWmcl;`}nQ-(L zN6PHJJ%#EO3*MXdeK>x9|EIT?^uDRTm5-}@w~sA9xgs>wEbfK$-Zo(6FVL( zeR+A^s@{g(-vmx=dUAC2FQaDWtdAG}T-Okt@l@>DE;oMOtr07&dfu46yFE|XWmn{7 zwHlLx6qQCMjUW+~pr#8Kla5_&>Ug+#McdM_saztfj*DiMti0Bx^)>5ymxcC0nL<~2 zk6)#)kFWnx(`4(Fu<84ZzY;Z!P73Fm51C$O^kv_jl9=$cE&YwTyNHz@V>oucktPJv-kDhZo69S^6Q%D&h@X%IzMgR z_QGc3<^^W{_0umheke$a{kc;!@0(@5n0OxxU+OdeJD0?dGrx}QS}vddeEolhzJFIY zS=74MCOdAAx*Vmkt13KJ<*{$)$0c{e4r%YWtC;=$X7*(5EaB~ryaFl()vi`ib5aGH zR|QSt`m)+x?DfCO=>ZD2f}_JE4|63)Cr8?_wpM(2m3nY4TTJN2r_GW=PSPS=T$)Zt zyHwoc*4tWdc|L3FjMTQczt(C08D4B&lp*!*OxnD4Umh>Na^7%9?}E?^H+y$ob2HX- tJ-X6+`GJ!abG%ia#HzTkOh5E>Y4(oj@2+LjXPGT;@-+rETju}22>@RNoE!iE diff --git a/doc/src/Eqs/fix_rx.tex b/doc/src/Eqs/fix_rx.tex deleted file mode 100644 index 9400656038..0000000000 --- a/doc/src/Eqs/fix_rx.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} -\pagestyle{empty} -\begin{document} - -\begin{eqnarray*} - k = AT^{n}e^{\frac{-E_{a}}{k_{B}T}} -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_rx_localTemp.jpg b/doc/src/Eqs/fix_rx_localTemp.jpg deleted file mode 100644 index 2b5147b93042028546e9fd67a3aec8e276d74ad7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16562 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 ZWw2^71HXgj73^(dTy5n+AkO~(CIAwd*bM*x diff --git a/doc/src/Eqs/fix_rx_localTemp.tex b/doc/src/Eqs/fix_rx_localTemp.tex deleted file mode 100644 index cbb191f8f4..0000000000 --- a/doc/src/Eqs/fix_rx_localTemp.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} -\pagestyle{empty} -\begin{document} - -\begin{eqnarray*} - \theta_i^{-1} = \frac{\sum_{j=1}\omega_{Lucy}\left(r_{ij}\right)\theta_j^{-1}}{\sum_{j=1}\omega_{Lucy}\left(r_{ij}\right)} -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_rx_localTemp2.jpg b/doc/src/Eqs/fix_rx_localTemp2.jpg deleted file mode 100644 index c838d7d45302da5f69bc98293afb3307c9bef6cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16284 zcmex=Bm<7<_#hv=|r|I2c$Mtr?gY7#JiO z7&yGzGZ|PI7#J8C7&ubq%mvX5MhpxBcV5Xburn}l@Gvki*fB6LFvz?D>jg1K@n{H) zhQMeDjE2By2#kin2n+$A#G=%^lB)b-9R;t%+|*))00j+a&oE5}1_ss%%;2_#2m^z_ zrU@)?_OVG5!E9y|V+MvvlMrk~JA-2xC@4qU8K6)Y#iJoG8UmvsFd71*Auw`7z{tSR z%*w#T%D`N~(9p`z)XLbL0h<^DgAYR@LlHwNLmop3Llr|lLotI6g93vWLn1>iLn=ct zg91YUg93vFgENCCLl^_7q4NJBw{}KJNr9EVeqOO&VoH8es$Oz_u6{*gfxe-hfj)zc zeMLcHa&~HoLQ-maW}dD3``!E16*5z7)x%AF4SWlnQ!_F>s)|yBtNcQetFn_VQ`GJ4 zc)4sUtSWK~a#KqZ6)JLb@`|l0Y?Z*KTjdp7frRyy>}-ls(yW49+@LCoQqpXdpl&HI zFV`zK*2^zS*Eh7ZwA42+(l;{FElNq#Ew0QfNvzP#D^`XY;F4OLT$EW*l9`{U05UK! zDZjMDR;jc!GsP+`G0ik7CB;-XDbYAZ*U&H}Q8zKg*ibjc*f_=9)X>5x%`iy`YJEyF z-1dUfq8zZ@Darb&IjOm+c_qdAhI)qjO8O8-Q_IeZ+yc0zSc6~5&ZZ)_z{;7)TDKuFHuEEjyc(WUFM5+w+Sc)(58+ zLW7&k*v`qc!`1AD_&6ui4#EgdEwtn1;^gGC(MNU#X0U)of?V9}Z1mxY){d7;fev8Q z5|RRWG`L2Ci=+@BN%3gv8VxRzLVzU2qp53%1s9^>o0^wmt6r{dZ}7bho|D8B%YpoFNDq=cx1xU`(QqO`24thj`do|3ADrnZi@l!Cso zzLt@?mbMni5Jq+m4lYhE5pHe~Eg1xo=LsQGd)Xdz%(#qMz)y>_* z(j7{Xt-7OX zyYA;|wjZ#R_H)*nXJll#Zdu=SeuYI{8Vq2((0tnIs%^Q20=p{CtY$3SJ3)Y(^>u@X z!U7yT>`spC^NyiA6*-dHZhgA-!7Eo! zasJ7Pizc5cxGh_?^0NP@!TW4ssn)HR-?9qw^yFLP6YtDB zAoW7~%$G>}ho(PnugdEG{BoX9|8Kh!_1v*1jE(zC12=zMbiM4~+P|5fd8htoSpAX-7m56j!7oiy{e|K!>q4kOHJgu(;`tI(~Sk&drrLm|1 zjGxzUsL_A8ULea(d#di1-+x_$v{&DJ$EDrC!2B$C@w>i;bkU39rVsPwUfeUdx^=I; z$8Yz!i(>xHdU96mYT9X@mFJbU4$qOZDp{Dn>_5YTk}FT%Y+3&C__5voQc?4NOvot9 z%}y_zr=OmC@TP5Yz>~Ze9*>o0z4_z)DF281ma|TOqH34j_t|D1o__X*6N8^{ljMgb z52n7_^Es~iBX{upgZriah}SL>YCmFZ+P6HX{prqt6RY0rzZY-taMuIIIfc>kQU*0b zvt%cHdbh`aRdnXlDMjT*?~?yBF!YOLJ(P?4_VfNfj(@j{-qufw|G?Xu{z!D+%!jNW zUHA5Euk!v`7p(VC=l2Qjr^iH|t8U;HJ^4*x-d^b{?S$UL7RoHax)1uU-O{cQPzh9U z2`~_KI3U{n$os5SMX<-NYkFUH<}K?}nRm9!p!VQ2d*jRy{hove6AG*@m+hTi6#BL- zKQJIR&N-ETX2B7rf`tLQ4ZnmkOtX<=cpLdo_P5Tp?cv*`)?Qo6`}E4BXODb-^4K{G ztz&dp>T%1>@m%Fu#fd+bA8tNkmDQa+ZR3@<(&sL}e=KjhWygcxD_@+dNL2~VXZf*o zkM9yM{Rh#$$$m3#Wra2TXIM3}YU=rr#J1o&@>wsn&;0RM|D#whVPY?E^!Hx-BQq|U zDp*xMR=el?{%Y}!K-stVKmTWF-hPKa``e#g{~6~0v3xlt(3L^-WX1I(;oG*0*-3x6 zt#SQp(;-R8a@{%F|292r|E=80zFNRGdrf)7#knU!11I@AXrHYUHLh45biGdDF3*34 ztUJ=a#^rxDZ))vYXKQYerhFw}>fK%S@$;V++>HPAZ-2DxwdRG9KgvD&{WtIhdRD4V z-R^1AK5gRd)y8t3Yo#=n-94PJs7sR}&{YJC`(8^K@8nu#>dudMr0P3L&Z-A) zoMgGRLuIyK#O&%*!I>Jb9Bv#ju=SA0nb`G8z0G=drNUg6iC#-(`Q2C&x<0Sf;jRAG zb}irTi=6bOg&Q5*nKIAMIAi;*K_lv$4?x!*F*Sk-WR4&%JGT~^v`x4!#b-4ik?^0l~IwRMnh(?*Z9KDS4?OWkJ} zwP-hmPk!z6MlS8EXzwH4V83mb^Kwghy>cylIo)?{XD{7QKgA~`px}2H`s6c{tYwJx9;psZ40rn+HgYogQ>Mfs@4GkHxAp^XX~VVYD^#P z7yM&4Vzv^$@hx)UBE9n0 zN!)T2QPx*uD_il--!VqMW67nh{~21Z+ZpY;%-6e8ZPxd&?Zrx}cNe#+8Y(;~?lV4- zBY0BuMX2i+TQ%?d+w5khU5`He^VwbQcQ5DOI9L19wB-7iF2A$(FK7N^+kdsxpDE+| zJ*9?&E6->27qynnJyNQDW8RLpbHcuggnHiH<`O!|(N!c!0uuRQ-sjDOrd_l6uA{*- z>3M7NMY|nOelhJWKEOIlV_lKI*o-9_0EBP(+=^XF7vwmh`1ns3RxQxe}+mx+Cjj$9Rc zM|yViXKzIb*8bSlf3#oNT1_hQSFN}IHviaJZQq<3CADg~?vjtsPCcSg&m#1n;eP1# z_}IUFcPyM$`d-TvHus)6&OGn%PTK~x)(`jh|GfSAFXQ{X`yc)@On()zXlJhWv6ZW{ ztJbyVr_N3Gnwq?`!^=l&P2<%+XZLbg9J_myy@@ev>qC3dqmOpiI(g)#ZZ{L(6lqy- zTczZfml(su$$bt_q|E>PbI8BwD#AE-t?I9vwW~dnu9w{`-LBiRQ}(f4%eTB$g;!D} zOM1hu$6S0{YHNG?cC4F9&%`FiH||MRf;XDOwL3nD96Ehup5ccVImeg3YI-I5?@76a z>Va?fQvSSLo42oi`RgCdxBfF+|N1XI-&J((>L2ZH7lhQWmsax{rm47H->%6~WYxH% z=MuA9*R%f&50if=|7+Lh|IhH?68}G~{vQ$lIQ}y%Jbm~-!w-|@{|sFV_$GCozf}5G zKEBPfL^tesaG%<3<(qew9ORD?TJqppD?`w=tr}l)+5R&G&;J`bb<1@AFRnWEQw#Pp zzERos!#}mYbaLhD^JWW+p0D21S8)8*s;$+JU0+AkNPg5=eK6Z!z28$p@jt_b)yWV4 zuD`KQx+3qsgyGAw10VZpww{0OXP@~?|NNf`-Wh-XGjP|>wvu{U6Zw(p@S!NV3RHh<*UBV{|rk1=Kg1h+gSgCX?@scPtPUEzB?VwZ)i$h zHQd|u&O*}S!EvX9As{P^(vZ(i5`42zzucs0Fj`n}UH?x);NDMlxGk1n6jKEp5a+iGPt+kZ9bb5bUiy;#8KcmBY}(~n-*1U`y>ygKXK zMv1jdho9WO#r(ae@M+)U$&=0;zbvu3>VC_j>o(C3|7JaVd(D>j*;HL8rcEbaiAK!% zxFw~}YTn&nQW|fc$o@IB=lM}P*Xu{tYWo_BZn%_OFPNpGsg~*fZUOU^Cx*v=bJ=QN zT(#$#Sh;w>ojXyEx<@2GEv-0gQu%tzJa@ka%x{}cd7Iyf-95YKu|?eem{QAwKSGmrrytgpeYYuZeNy(%lQPri_AIyme$Sq3 z?IT(Hqj6f7O4swn-n@MyD(=ot!T6&Z2|69IPkP=NZ9li;mPq=_<7aOj=88TjW3a;G zaX`o74a^L|(dPH=f2jB0A@BP7KLhjE-^Z^re%$Y!>;I5#(}jCg2a zn0CAu`r~=|k7a6Z!L7387CZO%`#XK>&s*f4#HbdqWIfAMXXgHz>&bDkA0Pj7UC&p4 z<7E1OhRv6vPU@TfZ2pn*TkYSIo3Bh@Ep1SeJ6{oeD6k@_Ht+G<{K~>LSwZ)`l^4V= z+#qIn@}a}Ay1iE6&aTqz-h$^@%FQl08mL(YEN(a=#BuORkv-Sv{|qcKy8jt^OwSAW zbN6qLGn>5Z*ed(d+zbihiC05T@BgS_eSJ|_>C>4TH(k;D!fSW_cTmR6$yFUkJ~fne zO7Kja_a*M!zxeB~_9gDx{`GIpKX>JiZnq>$xMTTP64g6PXGceFn={S#)Frv<%0j`| z9}*I>+P&K@Zk=0yRElr=Bkht6u~IirYzyaocK1|c?2j}?(Q?+4I^{BtWxj=c3;X<^ zLG@SsGwr+o8RD=1F$kafZWc71tmzTEHQy!Fd7%s=lvdu(!!h`iys z=Qqvo^+rtcTEFsH-+~f3@xAjyu5A7NxJplF-~DgdChj~N*LbY@Ydy2(%wJZ2{+nCv z#rIyZC|+{lTbo0X%}FooOkQ}pQKbM}asptNO!XNV%Kin(!K6B@#H;O)a zT;e5ul^qint1x*!H@)-Xm+iFXB?p(ioLCulp-Dtc=ZxpcwB*xtte|Un$bjXs%*0t=q`5gtUI()7zGKBa z=T6K?>-zgahWXd_{44&u_qW@vy|i+b>bjMQ%NKR( z=}VrwdqY!7FY^2b)$mu3rqqc(umAK{|Fg_KeV6^`zizaOzj?A&bxL`F?G^7`9%2r$ z>?`9I6xmzNOzmA#arNq4!@Z7Ai!Up0EwBn*bhjpHo=UmdKdDR86yl|q&U<-!_eP16 zw}qbft;w=)5C3r2zO%;dh_~71RWY_J96YDpyTK7GcVF{A!@d=}yxwoF@7=HKc6slf zOTVw4d-Xl!@|U~wZ<$}aHv9AD^D~3XtRAb+D*4qqbUIx1%UuKx_p--WAJuQ&f*Kl9~Tos1WK zuhuFmip&wSI4`#+cy;p*=BOVZGv$~MKfEjZOhtaD?diA7ub&>fKev3Ut?<9?8MRUW zw(UF=F?YWF*4E-P`{cJ)9RICU>G;><&+BdTETU63ubQve({c6>dnU_2m;Pfr_9yQz>HHredH*xCZH*W4vafuk8};a`r%Xrl zo8Gzx&EwbhibV!V%!{0x+{>6&Zo$PK-qM|^%i6ljVa)-i-)`nI zP<-H+VgI+Ny-%xE%^vi$Mwcmfr zHO7dyp8L^v@LnKS^3Z|$Pd24D zDgv7;%w1CzniCmW2SP6`uM-*FgwY6>lS|4eAt}p z_U2^{YwB->aMcH79)CFLbNmXg>)l`fGu-xDwCD5V<9{ad3)Ww^*#D&{eBpK3$Me}< z-7~+im6tEK=+bHLJsM`mmmB*m^xDQfvuw_${|p6%$M?ES&N_N|QqPt7&WkVFKZ(D* z|MfNfzYL+Tj$J5uo9)vko$DR4dEd6CyGj092NzD*aNy3_XPf4+J1m~}cXis<*?zu@ zr819k+O>(TT<~i9_qVpwyGwnIlo-UWUHjJ8gIIe&qzEAM>v3`1|dD7`Hht@VCp6mmi*;59wbwdG+nsdDcwf zKXZ{a4o6HBg z>Bp{JyLSDa(v~ev=lH~c$o_p*IoF5bNu zVsfH1qvrnG?$_2E3ZK?aJG(&p_3o1OyX|fq-y6SxFFoMHz5V4Yd~N6VnOaMzOYR{Lk=5;QW7vlT&JmQZ{w*636vUpZ+uC zXGN91nqadrb@|Dhknblmmz>Y{Kepw?0;WCP-=_ZDC+aHk`%~7mSBq`^&mOIMTWNlL zid5_R<}Cq5x7s`2URh^6m9f#j?V+E&Ol|nHw)tAQW%ZM76Du6QEM3&)6s3UH=Vn;8 zi&Hrz_ke-I+oa_mlqdQvYOw5%Z=WZ(>B@Rj?vN{s_Uya;ZRYie-S^Edw%)0^SHQ=< zH2PAF{Gu1T&K_Hv%6j;fxFJW%&Ru(FJw3%dVZo`lThiz7ggq5udscd`aoOE0{#xDL z+?~o1Pb;2Q{CN`O5zggMU{sOwRe9%X3TDznl^3K(T-lun{v3h@K?E z;F}rfkeBNIaIc>3X%Qh6oioR7=BWtC-mj>P-j?uWl3|mlZMJ%BWXea?JyLB`pS`$t z?ND}hx5u;Wsk`okXG!e8y28m(rRV)|hpSgFI>@v){LwY*RNJ^F%b>$lw&;n!id^QD zgHn1Y7N@JcPcVvj(tD=BL(;ZZB$#R2;^nuqZsmM4zxZ?7=VjMpCe$tHb7Y_3uF&AB zHdplS-bsh+Ep|?`pW@#m8B&ra%Ut!i=abbop&@C5>md%Fox9VE{WUU zUE}zu)=#YYx69$&RF?U5))|e54gLweIdj`zA=$!`dF`V4v;Xa1f3@AaKK}Yo$z9iG zt8L8Ek&4$kmD9azllIwvEN4~cH@)AZUsiwVkNL`&h!gx_u}`n=YcD*0X|LIy z+oApc1nPUjZvFUaQZK3$5x@Pz;fndMRP4?e&5zrg(SJ1WSIw`w)z5@})SCWhu>bs1 zZnCRL03#Y^F)t6i89j699XF>{E1u4nAnLwTh3ojHk8N}7D=QQ8CeIBz6|Yrm&;4BS zmW*)Q?JcXBcb8c*TRz&RzP+!!_38O{DxbyKnXNsZUwgD9ky7bhK zf4WwK*Hh2nD@B}tUMDTsvT@6X-b=@>NvBM5n|e*+5L=mLn#C*6C-c7Ag6BO%pWT;T zulk>%HLt{5sP66~?i(hzQ)N%@Q2%giNuB9S(`Of4|1)r2KbBl)S1Wz+)d#1$Vc9Fa08pSbxaWd5;Tw?5}{9{1Ek(Hp z4;$nU`3l}$_n%?ue+IXI4^OB3uG{}1$X2aOV+l%hg|5#JJF9%A$X8|kCXL0%p63WR zPGWcPS1DO-I(N;TsF!8tQg)YfTgrF0Qs4Z?w#H$b zr{x-W7pv|*DSLL;+wg4}H&%CY8-yNY|FQF+_5|awKbDVlt&diTSncaJpPOlz8m26> zS~T(f37ekg8?&C;alh0}{jlrUyHBRS(>7ho3eWBT+G{Mv@}J=VSJ%6oH*ZURTfEiL zUAT2yM{b`)GDn9kQy*)zpWgZU>nke^fhc{BW!}cgf3))A@Nj?mX937M@mS zd$UtzesEMsz!rzE;JLO#AM@LkKDtfVzp{6}*LRk#yNenO z|Cp|PWz{z;IQH_r!@=9~wVpCf=ILR--+7*=$5QrKL4o7iE{$bhg)X4Z;n^uv)ct2T z8pnENi>=lxZSU?U5k8lmXB~^FoNGPhj^X>;YfDOkHdXhU&ArGvb%|Bo{QUHs-HO{g zlX~4#0~_oWW7hYVcK^uRBG32Y^WL@h_E#lTFZq4Jp(8FV_~y4B=G&I9v^TE#8}7RG z>e)4ur*}O%7jJd#nG*A%-(Hi9I4r{ynm8<9hTOe-W0GfN*?)#MFyj51O zFqw5t(2{Q-op!JHW)L~8`Ez!@`kW_oCLgzD4cva|Nb!>I;o;(&j(PSj*J7!Zco-O3 z+|x60j*xLv)>nqYS;wZAKJG0o`Te>w_mA;%Ke>l$PQ5G7EZ1uE|Fbc;$=_Xp@xaM9 azXDzLrtxj(g3V}-(vX>5BErG`|4jf!2T{HN diff --git a/doc/src/Eqs/fix_rx_localTemp2.tex b/doc/src/Eqs/fix_rx_localTemp2.tex deleted file mode 100644 index 0b524adc00..0000000000 --- a/doc/src/Eqs/fix_rx_localTemp2.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} -\pagestyle{empty} -\begin{document} - -\begin{eqnarray*} - \omega_{Lucy}\left(r_{ij}\right) = \left( 1 + \frac{3r_{ij}}{r_c} \right) \left( 1 - \frac{r_{ij}}{r_c} \right)^3 -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_rx_reaction.jpg b/doc/src/Eqs/fix_rx_reaction.jpg deleted file mode 100644 index e656cd8362ec846c0c1ebfc76f4bbe26934d4c32..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2896 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 E0K~p$<%PwSRFvdYWaQ-K{vTlA=3o?I{K?2D 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 diff --git a/doc/src/Eqs/fix_spring_rg.tex b/doc/src/Eqs/fix_spring_rg.tex deleted file mode 100644 index b772aaf652..0000000000 --- a/doc/src/Eqs/fix_spring_rg.tex +++ /dev/null @@ -1,19 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ -{R_G}^2 = \frac{1}{M}\sum_{i}^{N}{m_{i}\left( x_{i} - -\frac{1}{M}\sum_{j}^{N}{m_{j}x_{j}} \right)^{2}} -$$ - -$$ - E = K\left( R_G - R_{G0} \right)^{2} -$$ - -$$ -F_{i} = 2K\frac{m_{i}}{M}\left( 1-\frac{R_{G0}}{R_G} -\right)\left( x_{i} - \frac{1}{M}\sum_{j}^{N}{m_{j}x_{j}} \right) -$$ - -\end{document} \ No newline at end of file diff --git a/doc/src/Eqs/fix_ttm.jpg b/doc/src/Eqs/fix_ttm.jpg deleted file mode 100644 index 8d9fac3fed5340a7a37c19f213bf45f051561f2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5869 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 F0ss-+LgxSg diff --git a/doc/src/Eqs/fix_ttm.tex b/doc/src/Eqs/fix_ttm.tex deleted file mode 100644 index d5a3238f82..0000000000 --- a/doc/src/Eqs/fix_ttm.tex +++ /dev/null @@ -1,15 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - C_e \rho_e \frac{\partial T_e}{\partial t} = - \bigtriangledown (\kappa_e \bigtriangledown T_e) - - g_p (T_e - T_a) + g_s T_a' -$$ - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_ttm_blast.jpg b/doc/src/Eqs/fix_ttm_blast.jpg deleted file mode 100644 index d4ffe05f129715572923fcd32c547b64aee902f1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4449 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 diff --git a/doc/src/Eqs/fix_ttm_blast.tex b/doc/src/Eqs/fix_ttm_blast.tex deleted file mode 100644 index 6871ed5cc6..0000000000 --- a/doc/src/Eqs/fix_ttm_blast.tex +++ /dev/null @@ -1,13 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - {\vec F}_i = - \partial U / \partial {\vec r}_i + {\vec F}_{langevin} - \nabla P_e/n_{ion} -$$ - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_ttm_blast1.jpg b/doc/src/Eqs/fix_ttm_blast1.jpg deleted file mode 100644 index 1106c627cbdc5c8d48cf9272513c799e4e65524a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8657 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⩔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 gAF$<%PwSRFvdYWaQ-K{vTlA=3sDSn#{;3 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 diff --git a/doc/src/Eqs/fix_ttm_ce.tex b/doc/src/Eqs/fix_ttm_ce.tex deleted file mode 100644 index f787590b8f..0000000000 --- a/doc/src/Eqs/fix_ttm_ce.tex +++ /dev/null @@ -1,13 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - C_e = C_0 + (a_0 + a_1 X + a_2 X^2 + a_3 X^3 + a_4 X^4) \exp (-(AX)^2) -$$ - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_ttm_mod.jpg b/doc/src/Eqs/fix_ttm_mod.jpg deleted file mode 100644 index 7cc67200f96bae3be7633d8d0c52ed76eabd1474..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10179 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 diff --git a/doc/src/Eqs/fix_ttm_mod.tex b/doc/src/Eqs/fix_ttm_mod.tex deleted file mode 100644 index d0a313e676..0000000000 --- a/doc/src/Eqs/fix_ttm_mod.tex +++ /dev/null @@ -1,15 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - C_e \rho_e \frac{\partial T_e}{\partial t} = - \bigtriangledown (\kappa_e \bigtriangledown T_e) - - g_p (T_e - T_a) + g_s T_a' + \theta (x-x_{surface})I_0 \exp(-x/l_{skin}) -$$ - -\end{document} - - - - diff --git a/doc/src/Eqs/fix_wall_colloid.jpg b/doc/src/Eqs/fix_wall_colloid.jpg deleted file mode 100644 index 8168d3a792d2e4dbf7d4df3e767771f61a57da84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17879 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 D9dxe2 diff --git a/doc/src/Eqs/fix_wall_colloid.tex b/doc/src/Eqs/fix_wall_colloid.tex deleted file mode 100644 index 3ed716c263..0000000000 --- a/doc/src/Eqs/fix_wall_colloid.tex +++ /dev/null @@ -1,14 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\begin{eqnarray} -E &=& \epsilon \left[ \frac{\sigma^{6}}{7560} - \left(\frac{6R-D}{D^{7}} + \frac{D+8R}{(D+2R)^{7}} \right) - - \frac{}{} \right. \nonumber \\ - &&\qquad \left. \frac{1}{6} \left(\frac{2R(D+R) + D(D+2R) - \left[ \ln D - \ln (D+2R) \right]}{D(D+2R)} \right) \right] -\qquad r < r_c \nonumber -\end{eqnarray} - -\end{document} diff --git a/doc/src/Eqs/fix_wall_ees.jpg b/doc/src/Eqs/fix_wall_ees.jpg deleted file mode 100644 index 0f99dae8f717cdf5456b943a3ffb7e246a1078e5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 106786 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 diff --git a/doc/src/Eqs/fix_wall_harmonic.tex b/doc/src/Eqs/fix_wall_harmonic.tex deleted file mode 100644 index 86dcb80a0e..0000000000 --- a/doc/src/Eqs/fix_wall_harmonic.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - E = \epsilon \hspace{0.1cm} (r - r_c)^2 \qquad r < r_c -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_wall_lj1043.jpg b/doc/src/Eqs/fix_wall_lj1043.jpg deleted file mode 100644 index 303743bf3e84dd0631cc4f1976aea6eaeaf90a26..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 10996 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 Y)CEiH-0gOsZ`3FKhG-+1jQ@WV0Hf%6RsaA1 diff --git a/doc/src/Eqs/fix_wall_lj1043.tex b/doc/src/Eqs/fix_wall_lj1043.tex deleted file mode 100644 index 06fc4dd33e..0000000000 --- a/doc/src/Eqs/fix_wall_lj1043.tex +++ /dev/null @@ -1,12 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - E = 2 \pi \epsilon \left[ \frac{2}{5} \left(\frac{\sigma}{r}\right)^{10} - - \left(\frac{\sigma}{r}\right)^4 - - \frac{\sqrt(2)\sigma^3}{3\left(r+\left(0.61/\sqrt(2)\right)\sigma\right)^3}\right] - \qquad r < r_c -$$ - -\end{document} \ No newline at end of file diff --git a/doc/src/Eqs/fix_wall_lj93.jpg b/doc/src/Eqs/fix_wall_lj93.jpg deleted file mode 100644 index 18e502cfbfeb8b63f4b9b0df3558f8192058273f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4883 zcmex=$<%PwSRFvdYWaQ-K{vTlA=3q!;T+GNQ z$ngINgEYu|Mi5|t0d_W4W)>!n|3?_y1sE7vm>8KEnK{_l*ti)O7#JCtm|0i_+1P~? z4TY5)IYdOw0}~5N#gvU2H*Ym|3QwAHMJ1@HdEz2f6N{9xrb$aSZn^yb76S((BLjmy z!@tumWP_M>o+mBdORkpP=Q;0aV)m*34CyjExhGyvzQ3s2v65jfQ|Wj8>(Wmw_`F@e z?|4=$Idi4VGV$|Hw{_gEH*h8vb28p4_S;+Hers1o2OR9MnLO*mJ>x8^Ig_V7DA=Z& zzNJs6%}wilwV8VXe}PJl;QpPZ8@I1adEq$W*q!xdbK5u-HpV%s6m9s)mp#iv;qSs) z4!Btz9UWbjS2>dAuh?tQRWVa1@9dr1aTgr_Gc4At;kqBTK5jEl>4GjX;Y~MgNOAtI z(K#McnG@s8>Ua5Rj!=q`LGr?RUhijF#A|PnduDvEfI*hQ?IgnlPG!S0Kh;%UUe|t< zt~jGy;XskkkqFP|v^{}0SEeOA=6+n_n;k2ut9Z89Q;wtXOQ?zKiN`Wc)0NgI-7~W0 zUo7&jO*$__FzW4x=SQFCC6wL1X-V|G@(<&lbD;6)Utp6S(dnRn6SjX!UXbPDjHz>(0q{74XbGv-V_V zpR=uBTiudrao@LIQ!(^Asi@L%VULt+#z~dgWPVhqlAFH@%qk z_CJG%l=W^8>AchBx8B{`biDXZ&7sK8!L_DSSIV+Gib>1G9D2De_HFa52k+i8T&Q3D z%4X`%m#+EqzZ~!NpM5g;$@YJJ9sZNv@C)1US2R7`ym;d#MitqHGV!CI3VyXb_|GsY z?4Lvk3v#k_wSVP*E!=y*_0B)*9xc#6bIF~@e_EupOipI;y~hhK*i7<2pt-dt;91ON z!864Vul#t&cECbwGvD=?t(t<{?lk{eD|>gN$?{CjMZ`R8_xihnG zKFObWlXGF&{CH^&w!@8bQO~CviOp}EF!8r`;E7El7UgUwo<@gmeEgx}WDbX7enw7! zOYDscw(Qv@Or6DjqQ{HotJ~~1du1E(>CdERd_Ila4GT*>pZ4#P`r2sKyS8|7@4{X0 zl=E&D-i=;TW6ytNM=e{x;~jVOobFn^KV>#I?eJT5!M=A7F4)S%{>WKZAE~^td1?5H z8$0ggecXGp%;Na$itB=(XY}8`bwM@%#*6j?Q}--Szkipya*=+~e z-zcn^8z)^?x#8>+o6euBc2w)_jNB9|cv|Q24!584WSoC9pKFe~UtxOuVoso7n$^-% z?z|6f@;oW1dG(k%VPSY(&aJ73ERyBl+MZ>9BW=(6_VPLNU%JN>j-SuCd*amd$dj=J z-`C!%pP6c3XeVXA>cX{t2A$j$$*DU&obbKs{nlOA=l&}B-hJia9;bfUIs-A}_RkYu4%+K4OOK+ZbTh@2H`NQwB6&W2J z%l~@*I`y*rdAa@6J0YwGp8tvBOFp*jz^zkHH%@(49jmhAG!th>=8gQiPUfn6TWYFa zSD$$B%iLLV*3!xI=Y8cjxK+IAaOP7>mTB1@-{hW6KlX5W<^hY^7UmBjSAzC&yzD>?o^rNsj{wV+LxdAolBpusL9El`pGcx{I&iEvdXe7@8r7|B>wRX zRSEvjFuDDTI{TkV+dmvy0FLe-#yi*earK|yY$>%x`#T$_`UDfp;}_T7e{1oF;Zq&= zdlwfMSI&c%PZaA<6*oQi__NUCg^zx$nxUcA$MICiD)z<cXezjbCebR@&y37A=DLDVv^gqMjtJ3nyX$#}hBKt1K3&*JU$4+Wu ze3#cLWw+S<(bAgPlRoi$5BnrzFWGbMe8YjDrksUGBHH$R(>Z_V#Ui7VI(a#{$=>~& z$_on_CfHcbJpSsqKW`Mrqx~Fj-W$ekdu@Cy_Py9XciX2&gxud+R9vvSbi7pkwf55c zbMO2MFUoj-P32;-MdwCpF4GO9>cep^Nv-pOy17V@H*Y$S-sCr`EUMb z{xcj+sz0y(a=P-rlRxMGSmXcm>3ipC>1*z-kIS1`bgR%?JL0!+PB|z@ItuO?rc;b-@R|Z6$o^UrtZ_&ye!x{GTxOKc8NH-19G5yYlP%f__cAXC%AZ`nTR%84Z^;*~#8CO8-4yM`O3!-u3?X?|=W6B7OTm z1K;=hqhW#m|NP_w=E#5Yx__9fp`)XF{)w!!a80d-IXuMEV)vEy`=^tA!@u`GLxkpahL`WPANHL6D}VaK zwWnuOm!FQAb&t*6=B$2xf$X+f%f76x(Io38h< zJaFRK_PtNfm1naT_Z?v2XIWdNq;us?Qq`Sp?^O@RH%;9$MbL3V-_dk`nR~}~-?U-) zCT7FFbIF?~)5i&-3znUHyyjTs9Df73KaF!6=I^LsKTxS2w`9IH=aum5_GJk`{4X6HsHCuiT3x#)W9TF(A!v2PFVn`gdXe%`X;*)~Qo z!CD`6uB(OY#sSWXGnrMm0q{6~emJejJ_Y zK6mHEW6wE`FKaA2KezF5m8j;6$#s3N%)<)wKD_uT5~*-EqwLmd;pX;75f6VfzgTsm zW2wDb*q_I}MSDKi9G?BmGW&vk{8stx-+b-sJGSoM89Gr=Wcd{H7x$;C^PG?`-C1Wn z=~xr{>P3?ze|!Eht1k>qaS56eTsQG&#B;r)@7>!UUd=fD_?ybSE0eS9dAFJU_&qgJ zLQ0jAJ2&wJ^r$CZSQhXk4`DojT=nlk2{uJZ*!V!)2f*nzmj#=X7ggn z@`;%r+#hY~eR%yto>0M>FE?&D-aLBm-FBD$jg9BNP5AMFC7(xbZ)?u9l#goGtKyd% z-7CH?Cz7=Kis6s$V#$=ryX(BSN|&yeowvNsGB$o|<;0JBs`Whk4nHyGX*aH%RBfLe zx#6@zV#URTNp9|fWyjyXPS~Nho?~gl+H75W+3hM@-kg>GJH>&kVA?T>XvS=3zu#q# zxcdtgCN5x`DF^~0{~1==N5<;?dH4L&?yiPq<@Rs=yZ2Q17wy#AmS5KGU z`f*oT|K5h0P(yF^(?u_LoptU!IK4C@Cn+!G)5PBv_di$E6`WYb;kWlDhfukAIrH`( zAMWN^g!23|=lQj#-&ij0`MI>3;!X1Dx4Gx}(W~vM$s&&7v(#XUQVN?Yrj972VeV-N^R-Po_oJXGxnr-WV6= z&9jET_loT>)dRl61(#-Ov42O%XvHk7E5h?!}DpqzZ|IeV# zzrv6Ir)vJgRtMxhjZ5&qC4W;(c7NVI|I|AzrkOF1|2ou%XMdhicqifd`nLH(xB5@} z$$dL%Q}o;EV?^8htBki7zp7dHT=8)*U#|0<$A%WKe|CM5?VmU;y~Hoaue|Qj1k(eu z-PjcevyT?z4 zPe{HWtn2zn+CL>Fd{gO06F$2&1)tY`H+j4Ka{A0;Ki1x|^?SN!zhcs!v!{-FEwk-W z*~j(4&AWM<3HQ=T&I>m#xZmHnA!4RsxMjN8>M5tfW^Lo{Kll9cYM(>bV|FkmZhAIx zqfElijqks87XM{Qc{@>1ur967a#2mtv75@(-f_oy+nFCU*(oMlh|07JZvQ2&TWwY_ zaqFc-y{${%HZjz{nl%5_jPJ`VeiSoEzstP8K4iz*d-1`H{Y^(JR)(GrIgv6`(|%nO z(@U0I2HDBVNgql~WS>{DCv3dyyma!DUk|6uOj~F5r25Pg1|8m2o@^X**H?L(M0xye zD;IL^X1o@%p4Dr^mDSveO=4yiixVzKTPN2KbP+ixIqdgbk6IZEUpSq>hCG^aZB60_|Bv|XLrq>@ppcSN%-XC zDC-+vzr@ul9*BFiSO0NLzFK1GoisD4%QIqP4t+CWzU3h;zcXthr~o1t*Z;o>0A_PX A@c;k- diff --git a/doc/src/Eqs/fix_wall_lj93.tex b/doc/src/Eqs/fix_wall_lj93.tex deleted file mode 100644 index 7372e55c15..0000000000 --- a/doc/src/Eqs/fix_wall_lj93.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - E = \epsilon \left[ \frac{2}{15} \left(\frac{\sigma}{r}\right)^{9} - - \left(\frac{\sigma}{r}\right)^3 \right] - \qquad r < r_c -$$ - -\end{document} \ No newline at end of file diff --git a/doc/src/Eqs/hexorder.jpg b/doc/src/Eqs/hexorder.jpg deleted file mode 100644 index dafa25cabec6733d1f5714501df3098b937a50a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 16870 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 C%3N3g diff --git a/doc/src/Eqs/pair_adp.tex b/doc/src/Eqs/pair_adp.tex deleted file mode 100644 index 07e441f3fa..0000000000 --- a/doc/src/Eqs/pair_adp.tex +++ /dev/null @@ -1,16 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} -E_i & = & F_\alpha \left( \sum_{j\neq i} \rho_\beta (r_{ij}) \right) + \frac{1}{2} \sum_{j\neq i}\phi_{\alpha\beta}(r_{ij})+ \frac{1}{2} \sum_s (\mu_i^s)^2 + \frac{1}{2} \sum_{s,t} (\lambda_i^{st})^2 - \frac{1}{6} \nu_i^2 \\ -% -\mu_i^s & = & \sum_{j\neq i}u_{\alpha\beta}(r_{ij})r_{ij}^s\\ -% -\lambda_i^{st} & = & \sum_{j\neq i}w_{\alpha\beta}(r_{ij})r_{ij}^sr_{ij}^t\\ -% -\nu_i & = & \sum_s\lambda_i^{ss} -\end{eqnarray*} - -\end{document} - diff --git a/doc/src/Eqs/pair_agni.jpg b/doc/src/Eqs/pair_agni.jpg deleted file mode 100644 index e0842225c6769d15fd38205c20cf52d606f29dcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15178 zcmex=oIr{vTiv|EDQ{cwTw*63@n1ILW+itY{G$w>`H|qMvW5}awt1(JSZA; z@q>zSQc)8pmzcPOq?D?fx`w8fiK&^ng{76Vi>sTvho@I?NN8AiL}XNQN@`kqMrKxV zNoiSmMP*fUOKV$uM`zch$y26In?7UatVN5LEM2yI#mZHiHgDOwZTpU$yAB;ba`f2o z6DLnyx_ss8wd*%--g@}x@sp>|p1*kc>f@)+U%r0({^RE_kiQrin8CgR5fG1|`Ad+2 ziIItgg_(sNL#FfEu$rZc*x#hF|XSfmipW(}_tk)|T7IkSbtct%i?Rdn$ z)4rc#I`+I|;^~+&M>F}xMt0_v2j6JkTDO>O;*z+maFq^Sg~}(#V^?w7pW3uXcKP|t z1@5Kw=a#RSzb$V2l0L?pUtDiB-*jat5eX9B>S=jE@&rH%~wF>~q#WIYz}OiM+eK@3kG&*5WS z(jB;UcJPkNi>H@f-BNg3i`8ChXTqK@&yx$U_ZNn(V4UbJ^I^$_T_;7lBxU`anNKKu z7wunl+vEDAyYctBYsI9U&L!`d#O}#>GUFrlOxCVSU-K!pZ^^bv{;`ZCsN&D|^ zpE75`w@A?gUs&C39snMxdHfVb&f95+@Vv}dsdaio%y;Ye-Kbn0%{@vHVGW&VR*7-iO zUa)QH6Y87fws@+{hiAKbl`efc?$gKX^q=AF^~AYLb_o7V>^8LEp1g&@fmwZN@pt=A z;U)KfGv2L#@k4`o9VmVXqO&zw+n4 zpFK}Jg=iYn&$S-D-+@0Lm#>? zxbma-KPC5w|7S=H|IctKbM?9fOkEla`0O85rynRUd+_*exY)JhcjGFqw*UR)TPAwE zCLqX$xw44;PnB-HWt@lj5YSb6JiL2U*zXB#jF+B0 z?7dm9S#M*H>``}?NsDdL*ICx{zA&G)|8T9{^PKwZE2ga1@{*@a71s7syWznu88CN$ zOW7)co3EIEG{OwG*pi`m#J&8gk)yJvfSL9cNCv+ND)tOJ8fKju62R*FT%-g*D_nT?0Njr@u0 z$quYV=156Vd)+#>=l{Ik&Hm4jV7>mYJS#)#l|WYp5hN^nBszPa$`w0>Y$?{Y*CuVN zDiQShY}(WF>Ql;^^zR4cr=;7|YHwe!{-NqebHK$tfsfV-y*inCHGiGzR?oLmVH1^3 zxiNE!)N?X7|M;?i?^JfbNW|-^8YBND_ab9{u6ixIW`f6>jhpo(PCaJnk+WFyVo&(W z{|u=%yK__L1xgV2u&e zsVX^X>i9=-k@t49OQN3l9+`>@vG(3C`?SD}?d{t+^%WP`9w<&Rn&9|E@ZPiu3=9kj zd<{Vt7+pnA@4dE7w&A0H+m-Z&Tg8*?_P-2ayb>6*{npm=zohn<{%2@<{-5E=s#oIH zZXW6~6E9p~x@4u(apIL^M8Zl*ma3qO4sr@M=bQG~AH4gYfg^6GzUv6TWu>RNgiEiAv54nS6Ot@A0j^rH0$K%qng3oMmzINMO(A z2k9B#Z8eypwEB8ioLrspZTqJicW&%?xp(cl@SKUi4c=r=n;*I3%0A`zj5GSIZ8OtF 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 BOnv|W diff --git a/doc/src/Eqs/pair_agni.tex b/doc/src/Eqs/pair_agni.tex deleted file mode 100644 index b9aa7882fc..0000000000 --- a/doc/src/Eqs/pair_agni.tex +++ /dev/null @@ -1,18 +0,0 @@ -\documentclass[12pt]{article} - -\pagestyle{empty} -\begin{document} - -\begin{eqnarray*} - F_i^u & = & \sum_t^{N_t}\alpha_t \cdot \exp\left[-\frac{\left(d_{i,t}^u\right)^2}{2l^2}\right] \\ - d_{i,t}^u & = & \left|\left| V_i^u(\eta) - V_t^u(\eta) \right|\right| \\ - V_i^u(\eta) & = & \sum_{j \neq i}\frac{r^u_{ij}}{r_{ij}} \cdot e^{-\left(\frac{r_{ij}}{\eta} \right)^2} \cdot f_d\left(r_{ij}\right) \\ - f_d\left(r_{ij}\right) & = & \frac{1}{2} \left[\cos\left(\frac{\pi r_{ij}}{R_c}\right) + 1 \right] -\end{eqnarray*} - -\end{document} - -%%% Local Variables: -%%% mode: latex -%%% TeX-master: t -%%% End: diff --git a/doc/src/Eqs/pair_airebo.jpg b/doc/src/Eqs/pair_airebo.jpg deleted file mode 100644 index a3259879f1689af00465286b11d3b17145a2fd4a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9380 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 E0IZHD5C8xG diff --git a/doc/src/Eqs/pair_airebo.tex b/doc/src/Eqs/pair_airebo.tex deleted file mode 100644 index 6c40b2ef58..0000000000 --- a/doc/src/Eqs/pair_airebo.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - E = \frac{1}{2} \sum_i \sum_{j \neq i} - \left[ E^{REBO}_{ij} + E^{LJ}_{ij} + - \sum_{k \neq i,j} \sum_{l \neq i,j,k} E^{TORSION}_{kijl} \right] -$$ - -\end{document} \ No newline at end of file diff --git a/doc/src/Eqs/pair_atm.jpg b/doc/src/Eqs/pair_atm.jpg deleted file mode 100644 index d2e6d704e930c2def4801301c928998f7542f54b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5474 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 diff --git a/doc/src/Eqs/pair_atm.tex b/doc/src/Eqs/pair_atm.tex deleted file mode 100644 index fce1db99b8..0000000000 --- a/doc/src/Eqs/pair_atm.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{equation} -E=\nu\frac{1+3\cos\gamma_1\cos\gamma_2\cos\gamma_3}{r_{12}^3r_{23}^3r_{31}^3} -\end{equation} - -\end{document} diff --git a/doc/src/Eqs/pair_beck.jpg b/doc/src/Eqs/pair_beck.jpg deleted file mode 100644 index a6da8a87d1c5f38313d1d35df5fdc618056f2ace..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9451 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 LlABaI{{Kw?!3$@z diff --git a/doc/src/Eqs/pair_beck.tex b/doc/src/Eqs/pair_beck.tex deleted file mode 100644 index dde6b6ef51..0000000000 --- a/doc/src/Eqs/pair_beck.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ -E\left(r\right) = A \exp\left[-\alpha r - \beta r^6\right] - -\frac{B}{\left(r^2+a^2\right)^3} \left(1+\frac{2.709+3a^2}{r^2+a^2}\right) - \qquad r < R_c -$$ - -\end{document} diff --git a/doc/src/Eqs/pair_body_rounded.jpg b/doc/src/Eqs/pair_body_rounded.jpg deleted file mode 100644 index e7136ddd20c2acea0e89fa8412497333f15cb541..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 146978 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
    rq3;&3JzOkH7u<$g^McPvD2&;XgQk z`yE_$>&JB0zpL!i)`sb~&X>sD6TSTI%k97FJ8RtS=BF1vte4LYyKZGSQ^Zd3ER1&r-%MJ=H0V?N|JtD{F_Nr3O-F!O%hX{%`bWRo43%% zh|b5VO{-hh_Dqf36B@P3S2kbRUr^lL=+MP8FTDD%&MDN3yBhc{hfo=%r^Z{~1izex3irBKaRDyGTLBa=%OaAMA+V*x#PmXZ%Q)N&7zo zYu%lF93P&xZtY>KzNuxXmHu*Moy8(FP_xjDx>R~)~2$!P7=pt@`8 z`5wn4pS3)!d@k$r)gJxsH7gz#bF2tnbJeuv(5fw0HP5ZtY4lILFlgeh$-i0Z4;I-! zm>2&cV6BrpQ;p$|&FY8V-(u6=`DJeUx8%PIbP|7rf86c+k+)}hz^f{@=?k;AUzd{a z+iGj(&3$>r%|A9D#kt|#&StUYZ+04%Joo1h z+B`QatCuIc>Clz+nu)KyEHux}OXV^QEwqp^nxm|Leb?vnE}%6E)BXhiwyM$D{CD}6 z{|vX+AGLblC45|-r#|hzObz#?FTdZ0`^od|(f{zD;mACb3wG*1o*yl{Wu0k%E9{@) zRXrQwhkvaDubtbGQ~yx<;=+wmQKwRO)k)3RqtExyV!!2_ko{YY&U8i2Q(C$-ntNJ7 z{I82ME+0z$botefnq&I~LyxA5JbC3V*>Uod*2Hi6`qQ_+s;KcR4{j@(RrstjEqBf% zqc^q|LHqPgALZD&PIcR+w&dlx&GX{hPOVDZbR+Rqz+#E#m0LDW*|>QcQw9H%@PE8P zA5Mejqt^cs?f%EL_0e7ab9;U){@5P!!Tr$N=unS$rm}3eAC>p)as8Noe4pIbvfyuO z7j5+Hcr!L`-Fe64*`y;D+wX1qZKFH=bo(E@QyXsduLwT(`OL+`b_<)9%s%|sXbzvS z`MIpiXQWzv{Mb8wba!Px-Y6o=W25!hNJh_Ui+X54oA|j$XL5PIA2}1eu;WPbrgxI3 zl)W{N`n4F$(20xfTKR8X!7-(2e1;26XQuA4J~X38HO5Vw+h0<~tT-@aZM0zDnaIDJ zvf@}ixNUxv%YAIu{^lC(RX^*y`*`4hxf8Q!t9R7VuW>`d5$*SrvFCU3(g+AnrGgvd#B5F<0{GGD3H|B;y=8#z# z>Y*3oV4pwf{Lhfb|3f|hP3?aMR@o2oEp}3MH|06wAKh=ZVSn`OGaF*-{)<4mfrW|R`=`-Rlmpw8@3wms5w?L z`PjpP9cM(j{#^E(CoUh(953$b>V0!-)Vk=#*;5ug7kAQ{^HB0?Z(PTt)rYyGS*3at z3nhBYw6Z|(ojV9&*XO?iXe`oF#P4?5<5@ag}d z{-5EP*pKhO)&89muF?Oo?w-iCKZ5@mIDP&zNc^*|c%$A{<7zj%aLvn?i)vhd%zU(; zZ}mOzB{$@^^Q!-LVrgBxbyuVM4$mr$N3S2gOnPx~zN$@~oJ35})9!CODv~zbxN&*U zVs+84YviQXo5-kFdD;A#w3734_@Ts)rUj*|gP*UQ{z$$1koT;@Zx)>o4I?B&wxo)h zeVB14R4=NlU~9OkXpq4i`*7_!FTrgLq&WO1S^wbCNA@7iT_rtVEq0r%c3UeWA}iy{Rk3SE9{yqQ`Nrp z>C0cX2hR5X(B5um^T+sFjpw?hdmNW+-SpvG@A5lYv!*SSvdWBdUHkU$!LD=n9#!ls z?s&Fu>*0zXpGynn)E0bc8E?GUt zU{&I^e0N5F{eTBu>bpqCR7V)8S{k<(r1hG$|>vHmU?qe_LA6hTzj5Af0tb|=nnIL*Ys`N6hH*8dsKe*8H#DnjQ!LzmX0#FoPe zJI=T5;8#7B>dwu>mOAIT>5pu~^Tj;AmBq;my|qvOSl+&=WpczS&Gq)zKJ#pE-^69HhA*5)O)_c2$F(z_{kXHd zbF)ru&Y_4>8*~0dgBdcu{BM2g%o)$tA2hGi`p+g;c!Ik6!yNe>~NXbkryoK4iaEcfO-&m86fH)w)C-v&8<>8*VNWRyk~Armpnx z&3@VG4-0q1xaD`Ol)AYrduGzlRcR7AY|To; z&EQ`ZaP+~aKgox#Ka#v&c*eLVl*i3%o<4Kq!NmM&4>A%oPct_jPZQ0&ek5u0AHG~E z$+GaqULBLahyU@u`OnbQPS(~JSpi%xAOAt|?)ae3RPZTfQ3mh#4zBjx&DfOWP`_cLl>+_xk*Yiu3{IL9OQDOavwQuK#XV>0GUb8WN z%+G%M@p|bW!AGWD7km+?|8af0QnTNO`Zk??I&(~07tTrfaZm4TcJhZg7R!Sf4_n0W zTA6&537)yD{M+Xb(8y6L(anSnp+-J+ zR(917;%`^~<4XPD|Brk9hv0vl%8%mv?D_X+-M{&tA?yQxSDk&u<;VU#|M)7h5AEM# zHvPlq;1A+`rM}XK<_nhEx0=gw{s`yW_|RVZN3zo;6Mcb-{|xC53~#Ktw=KQtQ0k58_Nz{;3_kwQ_{_|J zl^th_dDMi~IeSf+wA$u5d;j76>27)jy)~{m^Y#@xbGA%cuajrAPM*8%(DgIg35(^g zt-o3R?Z@BAbw+iE>RA77wlV(LeL%|ofUNdIvF=CpGC!7weiWO!?B#z3E@`I^cjwI0 z`mnrz;@9YJAGUYa$d>aS>tCHA)%y16uejSw!X~}aE=?^g{a%w9&pY*5<-XK-(XVs1 zi}xK%F1mAUs?}EeZ3aK~#D=%bW9!Lu7VJEhtZwn}@pNZ?nM0P{^CE*;-3^x8sMxVL zYg|8;^3yJyi>ocQ;q-^dvgF23{4n3?@|S+5dwyyL^Ynd>T&4}H3wshMvw?brMcJEcFt5qn-)a=`+83dzg_s@KZD^|1I!`=6?p36F=%d7#}jrUi3%$NAO4GfWOP@bM*Vm@3DN0sT2HY zxAtT4;X2J`uOIOrK0mzQ_fPf(|FR0H(=ONF{R#c39r96a^}1J4d)POVpG%($-;YuGlG_Eh-_VIQ)bOOHOatokBmk^ zU&S>s(~S}}F8fx^i)}pe$Y77PX)trg$^$!}OF!G=suQcDb@1F;J>`QR+FYl*OSY|T zSlfBz@s6U3H961UKJ8vR=SiiW+#JKnM;yNS-()`;{~;{?ho<6E`AJ4~Q zEBO{b+TXsPWuM%QAN2tj>ZD#v*~IDonEEJQ=!E`T+d8wwc4CW<{&=?PLE#M58P6ii zoM+nS`?nhX5#{$H(7Z%cifWiM+5+x#Ignx9yMD@*mz-Cvs_@ zW^{$(ma+{$8pYecoLFm8YxbWZs5>H8Kfc}h(iUCbJHoc5uYfsmSie0~dUP8ea zgFTirAHEDa^q*mkrEboxZLw~pS;42XEl7M-lg6eOFQdsOLk7*awMc+ z#fn{lHaVN6!?tA}txS3CF7Dp``Nz`=pJO7cFD;*uxH@H~U7^&Mzx%|QEf0wrM@`W< z`7qNrF*EUDcl<4ZWAnFv{d{~2Vz8b4%=~T34^+>;HTj$U-xd4QUQ6GOH4gmo_5<^y z`-f_^gZD+wJMDYTrt(2-@!?r^iz}vm7u&pdZQt@0QFmih$_0&&a<6+Mq<#2NjGDgm zq{o_1zbuS5Sn%OyU#!#8hzrX*&J@i_lQ%h#_&m-lU?Gp2KD%4b>vN)tZpPmxFAWo% zYFQm)*?k~k^O?c&^pfO>;s&?3}Ars<|?x)oX^-jSi=h>05f1 z%r%!>amxPe{6A9BAFU6@bM8-_-*5lH?|oNT=ZETVm;TQF&ycC#dF%So^G$YUR~BC0 zQ@%1|*W3P)Y3t#_v0l zW@0h9`G>RBsjSoD)1KTcOFVqz)x2{euM!GhcN)KWJz2c%dBq)(beVe*Dw|{M*hOV- zYo9kd-q!20YP-6@o`jd)}Coc`=o|ss_rSM{Rsn)iKQ=d-xyOhi5=yS>Lr-u_hT+vGU zu0@rDgWYx#TaH2-A$XK3nsB{qN4_BX3Pia%~|+Mib6 z_v`wbuOGjEyYhDrD25v4d1}lb@$=X4{)ql?IrMU_jo^pihpPR@vg14N^XHfDbw4uC z>~f9qBYl~QEm^^@=863Xd>k+IqRdRVqU~0#zMR65hXo=#P8%M6wpH`VKj{x39YomrO;2QHp*ZDGU7Pj6ytrY663%V+l6 zW>+a<@YDJ5;~nq&vQloUd3PVbbS&vdcI$_b4L{DDTV^cU^ey1b=NDJb{76<>-nG1W zp1-s3{IrM_$0dVxPAAW(QT)%qlKgkWe})Ge{xf`tIDd2Y!GCHWj~~-j{^s_>@x$^X za!Mca`|Gp!GyKu|k^D&hmhiWuAH(JvolIUSm&+sx%bk^}>$_~Hoqy@Uoi=CQY@g~$qH0Lz)+35xU0;9RZrs-A0 z_*v^6f4=jcv1HrPB!iu$IexN=gc~-%5+4yME2T9(T)f&hC+|@a>q}b=W z+Ub|UXA3HFd_Au`;yM3!y6E(P^*Vg&x+hmWjjYq!%5`(ghJ5kPGlmv#Vpb*?ojIu=eAa9e-7``g?fXMe~4X8@fMmbm{G|6|$ZZ=Dy{9lS45qyDhJ?f#aU zeGDJU51*I((d_lHZ23oi->WvfAEmv26fgb}eIWeSe}<;_dqn^Ci>+Qz;qEr=ci`ne zfrXX2PuI-yDT{OS>}V@LXc6;oU3@Te-@+q1-}7HR>NHPlTI{@spWc+2^S2#;urg_J zl|@&{hJd4wUS3=s)Kc{4wNk;iOQps-m#>}wV6mpTM>FN$rM)rxjUMJK?#Q@!G-&bH zIotM`Yn?E*yjU^I?)2@48>f8!;ms|zqcluDaDDKt72$2-+`l=0Xa0~s9xq&}QY&y65TN^C$4bvxc@EBhW3P% zgvPEv^)e5acRzTia`-TFuxY4KP5#zXD|UySEx54cdH1OoyO*s_i^#ZkFevlrs;Q5z zEV?xD%N^0KLkSg!TQ|;lb>VQrhdqu{!jC-4GF$mDgdYRo?#f0+MP`J?}l_$}-WrK@k0_)Axm`KJ4S z*f;m#eX)w^hi@&t618mpBL4*yN%GuB*TmeonfY?{59_##OVk4|mI}tNcpf=T+UTJ? z|K}dH)aElrUNX8}hcBNo*s;o@hfVg8#rn?AyF%`1%`Oo!jI7ISIa_cwIVhyi!Y9@0 zOO~I_EBQI8Gh)j4J1h3L>dVMRuRkw8M&vQ~MULH4j^y}l%#Men1B<_hnn4?=I`eAAuyTRNV zamm7xDH~0+t7Xdg`SpZOX(St+y5W-+-+#{7XTM?T;$VK~mpl5VdWpRFkfPeYQftSZ z)i#e;UR>K*y6M$TG3(#{?H1ya@~PfzAM?!@PX4&8+-Yviu?nf1{`?6Wr)*kNYjx%I z&;CE6)4%QhyROE1b=_^T{|uY^-?Fc%J6X@Y|H0h(8+qinr1#sYXTR1N z-haa6%<>!eGd{}imE--G-@K-Vb;*l=Z2e&$H~%QQ#V?Vy>-rIY_LpJ5rp?XI`FQ`& zJ8k)J?&;|@?%|SOYs_Mg{xLitsTUbFO*GLs=DFGG!xDeK8y`zbKie00+UTFg!#9hy z4n16PoHJZ@&f||WX6@|t*(8}$>tn|?x2B%&$;PFc=gm%5%AJXO{_+6F!zU%j!4tCL?B%ubyy04 zcxC>^vhBaaqW>sOew?>n{0Kiwjpc`l;D-{glqWej1Wx8D*l{c4BkS zuO)ZNS8853xjLXlxL;@0@3N;-MoaCJ^-evVk!XA;Y1KlWeyydmLYjN#tUk7_cuLBI z<(#S-2M=v4^cGY%S*%r}?&)Q!&X!ewP^tdG(mL_~3{7kQ9kUbryK0L(!`&L4>+(nE zY5geu$p7%puiF*#ZXeob`JrW7aO~}uc4}6BEv0wmLobx}^Z#f&_VP;Sd4u(H6JB3z<%#p0?XSCTrQg~p(Un&ZKG+)q9@c!;OHZJzt=}?7a;G-hHXh<{;~Z(Lv#B-{)*e* zbU+98)E~5}f3UMo@WZ#Y>uMB!7(VuIyU$^t_0q<6`Q5B2P)f^xESq)f{E_cv)6&$U z>t!mKAF=oDlZ$$FeY@GO(Dhwk-ZNEHyg|O#x_w6W?erV z_ASP>eZKLbhZ`m4uz$V1sHWzJ`Xl?MYxP^odOyZL{QLZX^?wHD{|tvtH$N8m7}v{x zc>Cn`W7Q zy!!EKqBC#nVyD$d&kJk*HgBCK78v?6>E+dDi{p92=30Hxc3P@+xNvicwQ+}{QN84l*@{xPr4{H^oDJmRDI!T$_5$;*Wx%o{AV~Q z9WVYP?$)PU*WP5#3P1Rtfj{f}Jk?3RIM(Hu)_2ZwZ$Eq|%PPEM?UufO+-=6~JNT`S zJ`?Su3Tuyw?3lGqS==(xZ5_AZ)D%fk_14gWiZf;W9gDeMRi>nN z9q%=izbz9x@yQIGn8KamjEOG;jwgM%aVnqt@5=Vm+5vr`{;zC)#N21>J6n9_eV4(E zIetbtCc~7@yGSw`TrRXa{Om_Fn|BH`(5luf1hW{ z{?D*E{;hN3igkMz)Lo6=G;LQMPfgn8Ki)FaCb>T1&3f;=b@HKqX4g12Y~5`2pP~DY z~*33!S?$bpSNE#{m;4@{T#G9H1JSDa_gxNGjvonAAO!Rqw8yo zrCc~y$@__qUtJAYa{pUcX37(`3HX>nN3L;ul|=)${Ffd~|b5{-#r=E57WU`mlSSWv!2!X!534TZ(O@ z7k}*xJ?I;{+NoWY^VBwVuKl+%9zOiKO5~nx@Vv;dJ$GgF?1eQvkDs5G?A4|gp;K#h zvrJE@*Dfa2^3vg}D>WZ!9-AgD_4upT)h8dezN&S`**;*I)M-nX$&1Cjnq~F!mgt#`Z~K@(s2^T^^1))63n!ot)gX2R#d+HpqCr{^GIdND!J|_ai%)*==~N{63elC+XJDB|ZllULe^nY9{f7jKWujkok`JdsS zqaDw`ix+D&e%OB4|Bs7vS>56I&FpU$uBZ|Gk@;vp+rLX<_u2M8)Zh4b@jm50@gLWB znRNGetz_^1Q~uz+?2qJwCqEoNYRBGu*iQ6EA(zwSiup(1KdRL}e9};2R>XZ?^^Ox8 zZT#c=KhOCr+x2jbn%XjX@wNvRI)^nMc0RoycJOaK`;nd7l3Na>mAndBd_*GCz1yNp z__TK5;YXid?T?<3dPB#hVz>6vuw}mCO`rIr*M?io)8^;8d0jMp^TRohr5g@D_{?MS z;p?Y2%M~B7H-#AN`O%YFv)K0R%SXwLhc3;jd-->9ss9h{N%aTq_hG~DKd${}I2bO^XCwa5Um#|-Ki?1kkfvkre1qp(t_*H{5wJ2^u;tum zsT$|0iJv+AjM{u{%u?q*D7x{af+Jz0N%ocXPV-bRte*3qA={t7=lHob8zwKE?#$gg zeewja=|V{wI|8Q#PkCgtYHGpOLcT2@-z}5YS>JOc{b%onty&L_etp$EFYd0gaN5-~ zA0%D1Og;u3d2Vzh@nzkL`h!}a>BIPK_x}i={ucCiTis%YQWf#_317a_6FdZ`*cxYjuXpr&Ze9uYOdE zcGfzxGV#ObmX}FIb+TuFW}XUe<(m1P|LM%DIVv(wt>(U%^$$D+wk+y5az{)e*pAK}aYxWbpko&W7w!+G)Yqv9KX``v&1 zXZUb&!H?RHmmMo|^>s~dw)dILHuo35`C`$(XOBHU96z#G`?wtU*1Z$r=JW17rLyug zkM`jtF>}2m;io=sTrcBwqWTeZxJuEjK#fq*nae*;YO^!D5}r!l{o7 zcj(C3cWt_5@atS~%k=FLXRgantM-bRQ?y`j%UrGEbDwoiEvcQp{dA(%j>D(U8SJQ0 zi|jjNk^VaHc)|x!?F$d*q`VAYIx8t7@UWYN&Tg@N%bO2hIeMi{D1@U~n(Raj%Uefon!{?zMXQS+gMG!ym1BW$>aLTQkeF|4>azASOefWEI+sZW+D=N&c zy*~0QyiM-iHEU_^`&?P(R`p%)_Jlv2&tB1OGpS9v)41m}bNl+g(*2zRP8+znv)mnc=gC{ot=+A^RR`iUg>Xf#-cpu<>|IhIlGOIJkUy$ zoL6t5Cw}62P=!|HTKjd6HUuAkWVn9fnr-ux_0A?n|F(Z^@k%0QvE`Ypz`)ZVX4u?6 zXlGY({2w>_Z=SmA^FR2+x5;t;c>mk0{-9fp>2J?JLEVSyx5anX1pZd9;kodiA$@(@ zKDO>7{~7qU#0&q}e)v+|`T6WM%8&hF@N^%*g9gY^<={Fc9_WydT3+LkZcdV1Aq&W=-x z?xv@fPQAKzrp ztrM4(x*vUJA=iyPd6CYHy)6sHomuBRF8tA>Yoq<_-@Mi5bU=$nQE$maT1y7&yh08b zL*p?Y+$w)F|69S;{|p(t+~3w*wPUZ*zha;1&r=ar&-|nO@zm$dCf5C(x71tplCHd6 ze$nK-xOdvEy>nOJd~J1Z{tUga(#xj3;Xa<>{#WvK*J-m`rv7KRwVGKo(SCcP*Svxa zZ!bm8(eP%r3Ou$VGD#$LTI%}mz4w3HGoL;C)yJyo$T5qfjeVLrPN&ngX0S$9`>#A# zAF=!JXZ1H%KSr!varD!%W$J=KhP_^w=loqAa_P(2VxKD|vDtnbu9@T}9eeM6b<5nK zbN2%-oBA3DY@c-LKZD~slkPpc7pXYQy!UQ2*B6bX6;}@@ zWn4Ov`1Q&rbI7Mwv%G_C*H?H+&?Wo%F`oij<-YQeY zu-+`=sa9K7U7j@8YRW6em6um?s%rS@dKq;UX0D#ES$BT_2KG0Ozcng$ABnU3JIg-h zeS!#Z@nktKr>1EFniousT)03YlCk-(t5Z!NFr-S%X9sF9h>nnax%P6eT*i`*``hbeUzltETP>&5<9DiO#XnISu19uuA3nD%p7GG=Wt!zaWuqfk zjs{Jw`0LhU@W=A4ZI70dXToMXol~F9LyxTrJpI&5ptWjC_NDJ1ezxk#Kg=_IRO56; znPhoKZa+wtf_DzkmNj zpugK}C6m(r`_%KZMH;nx1m;cxmM>Nm-A=b1$KT#u8!s`sUz>ksFL`F&hA z<%|zMgg)Dy{4CfAG?3_gjb77=PHTIge|fx4-z;m@w`3 zBA??OA4@)NT;Fl%+0Es=DHZROjszY%%pWvOZ77(CvU^9r z+LZeXcONNS&;DR}RLCBa51%CuPdv8k)0*Xv;*w_v9J%mtj+)v$A;>mT;cZ?55g@K@Z&&O++$+r4kh%Ih??{pb{% zTy7$GJ4@=1oZ`ijtvj!7`RgQgUb64RhC1nr!WpThbM@qor|xVs6D(PM`Pa6>?&F6U z-IbR%Of~OZKFdz-bVb+}qmF>cmV5Txo{6zp8(Q}2#7UbTt(bj$%H~j~{ert@))Ypp zGTm@_>Ffl}N5(xhJK9V$5A(XUg+`m6EuIm)J}~&uVg9yXze+aj*yVogKf^}(KO+1G z>kR(x|IhGX_kV^Dk^TIcuOFS4sBk|d&+(rjb^VRzhvGfg{xi6Kj6dox{3q)ATRWLQ zf*(rk`LDTrJU74eBl{6~Ry!H*>eT#Yj;mhos_(K1`Ft|zSKhX3F*26Zo=e)ZJltTq zA<|S%?W6rMDH;2=Ust0_3V+t-=p}copP71do#Ar7R-M`H70qhvXS+?)E7898pvSo< z)m!)AmHBnmod?rp0;h&YPBV*1q4z@vitn-Vd%`m!e{t2eI>7x%V2 zo@6omZ+wVoPMFzz$tRnRJe_>>*-bZ|f4{eIny%a;D;6*0n3(%Wv!vI|x9+xg=90_0 zUzcxg-RfcTe1~qqH^F$x$6GRQF3T?MIpsagbeWZeYxl9>gMLeMn2tPBY?-HI7`p1A zXymb$*T*y+L*~l42We`2wp5vP;j_`N8K-ve@WvdPY9;Y&hL5RFE|;EPuT08|LlLt= zma1!7mAtk*G<(WYb%|xS%hR7P@A}X1pkMxj*L&$7-`+pU2XW`eZ;IRcIMzFS$MvtZ zLC+sdZ@hFn=DL2~l6_Z9^93@>e)-7Be`H&@^1iR>yVd1uGs`b$O)oxMyu$X(rQO@j z`2Pt%^@_0nR_=Ur7njs={x@siOp}|lp2uqGY59~DD^}HPeA1IEQl6CMFMj5u@Kn!p zK~ufvoD*GjF8KMJSJ&EAqc+c(T|C#*FL?K}qTP+Z^b-@4mqy&ooE1BD+1zC>uTA?V zRW>&Uni_ zSn=wxwUMWmdTrJ6JXNaY=X^IlS zDtRa>5xksZsf3fDmtjv(Ptqh$m5G1m)E~V5PxsnBjT(*r3{7?Q2QBspuJKKL9Dn=# zw@V+?+x6DwE;jzV{Gc80-b*&NMb|H?pV?LxXZK_2hwpK$+g5LHe_C)m_i4)G6PwQ1 z3;tMmP}0wwz5CdcpE|{I+UMhhMZbnNA4*(V>$T-0pK0dRIa(jK#+e_v>?NuhJT2VD z`RUQXgT+-9Zw_s9e)wJbd4%h<&@+Z629jdYEoZd6L<>z{g{++yJdH_UwbZ0pXE*tD zYab2kmGRNIcwY12-^oWFf7smqLj8~U`Nz{%{^qMcC}y9z`+bX5=+V|2KjI(Uzq$J0 zrI)(4E#R@+qq@NkKgc=BK-SWO^}erHQVU=%wBk>a&cm|)bm~MUG(T2}+l%x6QJ}6p~<{f|QR6vWdX4qUE zf91pB``8X$ez?YzYln7p^ClUaO-Gjc^IIfsSkF8u<;N<+sa9X^d^(e7%s%UH^i4m} zhmG?jPxYvM6!<9rL)mQK{!Q~5K__3T)$!k|(0^0{Iu$DUZvMC4zx)2Fzpz?+Z)@U* z^vB}I`$b;XnfwU-Fza&UrNV{2kNIU@-P8Utcg^8Nub1f-$+zBPyzs|WY;JD)+MB-m zFL(Y4GdF*f8E|-)jsC$KG4q>>Vy?AXS>%{iAHA9C6=Hm=qQ*4F`G}P_XWN;Ie#_OZ zi@O%Kp8e6y+;}YcMRLrC8|&Ln&Gk`>KfI%>YiZ2wzKu7xi$2l_TNpLv(?5Ye{+mxD zx;`&%n-=$RT|}SEi49-s_RF|NS;l4eEpI#a@RhTy^DmqA6YXYbAT=NDEdDM8ZLr!f z|83$U?|iAcOZA)N-@O00`Pj8twaX^5_x@A-qy8bkV^7vD+h%{&zMgyfdoD#EDSB}& zC^ptReaY!n`{riro;|W5YRP1;vr{wzmxqS2t9ZBdwttH~uZ`k|{|x_xxOXJ=N#xr& z+P9VTnmv!*(3jYpAAZr!m(>!V7piU-9VGcFC4_&p^wT;kx>kVSvz zZ=Iqnaca4~bx%mllErdy9v2o%t=qI*K3794Z*$Dm+F3QHrf->U@^{wc;*cvlMeZz3 z*EE+uZq_Mp-W6fv{L%ivwfN1?+ZO%yznQ*k=a1)WBmUTZ zl-NAM=tSO@_l#Np^sfsho>^)#ljGK^bMxhohKhQmSh{3iSQu^nC}uT3f4+Ps*A=7A z&_{DlbG`|A@X97HbVBk5uXiCYZJgFdP0ccxEBQB`+kSPj;m_R_C)|}!Zq_+8Pg#Gu znm+4{>q|DxX_s|dwc05}j=y8G&vHQ zZ&usLMRy*1uyj`PN8zPmB`d;@JX-BkDsyF@|Dij}<_jfT6mv)I^%D7Ux+61bdDp5r z8%;LIxXvzqV7o+Vl~+WMm~T9D^KvJFDbufJCayf@>puH~|3BWpKej*izj^;#>JRP5 zYgPA%eti7x?SF=*D|Pqgsr)$jcs-wY+1oWgn7>7SVDGMRU0zfAh0- zml(}CDaEqRFzncsvjtOD{bwi?{d{~)jq=Ctf1K6-8CahEUGS%V#h=h0H-Gd0JAGfc zPBl9`?E9|&41Is1Kg1u{HNR_*cX>9C*tPF=n%ACOoc5pL$YS``flWP;}G5C>Xvf+!S+RBRy{X|v<`|dR5D)2JgGkfx;YrfmdZvHt@fAH3Ru|3X9 z|1%u4+$a0*R2@^tD|^BEJpEh!5B@V8)D?DWdYZ8BO37OOi2n?&&BoEozEm!neC(g> zkMad~*8f^l(Pe0@WwiK5$Or9?AHNTu6Y5KDIlXkovmZUDg@Z-CLLYyX5;*+f`Ic`6 zD>+r0&ivS{edcbs)Jk{#sTxkAuP(0lzJK_c$d3Bf9oIWQavSs*{h6Bjqv~ea)XYc4 zoad!`7Kdf6mDDk_Z!4-(IsNK#^Qw>fqCBcuMu)B+@sqEwKj>;x4vO`i{~4N;Ych8J z&|H51KSS2Pv+K! z8(v&zd*;0N-qw%7mecCPEsyNDwAj1HVp>~tl&K-V{?gV{JGw2Gw;l^Pe0{Ok@~ayS zP8o`Rh&0s-Y?_v;v!C5-t$a4uhVzHcEUVD^scRE|wJ>6x>`7xe<)fF69owhOJv(iV z>BPr7x&_^(d2GERW_>ZPInAh%{M2oq+~S2@N3Q)kChK}_>CcV-8CWE)y|Yig-!T7! zZ~PDSeb@_0bM2yh#$sgXuw@o?}()GwrVdd12 z?g*Ydwdr48e=I(DpR=a=!}Viz;y>O#v~S;M@x!rpVO&g&!-wlf>-m3_AC>1@zsG#3 z`nR=z_UT>t6P;fF@bq1&L)Q9lxhJo_<(;0V>w0B&&D_@?X7=Xn=Wbr#e^yRz9=Fc& zV59XNN1cS0Hn(xjd3|28QvJ<6xjE{AA-&64W_R!HUw6=5GF;f3clz(jq>Y;*q(U}a znzg#K;`rD4RZH3Cx^{k>cPwQ7?m+*E%Vr1tS@)lzN$yAdq2_OKKaPJq584C9TO;>F z_jh#N_5TcV`!nX>{Lk?4ddnWsWi{3pP3jw}dat+FNz^D`ds`#9ICGcX^o8yp`48^r z{&K%_!|lkIW!a|dd)~fJ7Z(pV7cc(3@48ux{(&7lzxJ8!D{nbr9CO+zvQ3@0=V-!x z>B95kKf0$q6+W7%ouqL!QqKLDWSBSqeZQp=Phay#nXC?6=`?-9%hc1I6^GXO^T-rc zS#FCy{Ik}FRU+`))UpKr(-)ISL))?A&Kb+53asKeH>n(c{AO00SS||EZZD!@7AKi!TR4=VDz0d#p zmf2#KX}j7cug$o%L_Df&<+AwOo~nDFwtn66ZF_*Hit$mEoRcv>)~Jcgwy$kD_HaeA z!Hf>8(hoOQnY@1Z+VMTtmaJnTuiReRMY^uO`7-5fM)>;Hwf=%_;OmHYz6@U&RFWMu z=~l?A%Y}1PwqDb<-}7hQ-v10u-1P@l->=VGl7ExmW7CJL-#ZgNw*F^0)GPkz{PFYr z|IUB^r?O2W;i~?BhIC%;N89Fp5c(F;6ELOg^}{{aZf@Ud=U}$&neGbr8&>?YmZ`s* zywXOem}{%CM`CP*-(1(W*{MyLRW{)`Lr@~k9SX^<6~ux zM^BrV^YCo+nzQoM{A;SsZE~SY+1)1ftg`enSnM?`Ph{mG`&DwRALJYViC0)3uIIOt zs<1xvpMif5^Mki)mmNP$Z>kYqkQpcTVS1a1H^-5%DEsz5){CNUW?I?J%#^s9pS=85 z^lhg-?n2L>y*QFoD6#AEk)+k3N5WTJUKzFJY0#3LNee}us@+}4aZDiEO|U0vO45|# zrEXKXvgS$^E@yeJ7qMF1YVuUC$)%A z{STGze}r%UZe{=JN?Un8SVo=Y@tF2ZOU(GWY4QCG4T^oAs;JLX` zB`>bGXs^-V_APIzkMNphA4;{XLSi!$_fEg2>?N{MYpbYM(O=#+iMJ2C?kTtgxXKu| zl}~IbRB+){>A7Ud#h|Zjyz%LbjjHRGJPj&dX*TDTU-0C>p5Q6Br_AaJ>IuC!u`4iI zWs=8(g>LhtdSz@Sc3fKMHCHOIXwIF?OHD0G&x3+ink^QYvs}|J`jnsVPVa!MpetMM zT1Q@9|D`wX(CN@irP11JtwSz-)sE2L^48mbU*p^LIr?wbEuMDk)2UClB6Z)b%~P7h z-Jw#ktoLzR*txY@p)b$%W|h1SS}D#oWz`{5%_}Wirl@l+mvmh#lQOF|_@cPqQZG}* zuqn^I)@mMGYBlA_!=O12t}L|hGn=9=sj6{G@8y!Kv+S*H4F5B*RR3paiuj@ZNN(!K z@I&<<{LkMsKYY*XLTPqvwd2(->zn3rY}s<5^fY(Jdy~7#&L6%+1$?;IyYglEhQrlM z<1=@;Zap`>n#Fup&9v_Z$CXMGK1%fLTeP-$eKdcR&7G+agYpIa=jj=htUl$pRqV04 z^rcx@Mwwn`XFSRbKIVA&NN}rHP`}E{A~%t&gGY}Z+Nz-uyq5FmR*R69hrw@;g*~_T z&=xxX#QYz3yW!vU{}~=^ng79M{ttED-kWzO6fUU(Wwy{LnTm zHrpjO$VkdG(?`w}_1aPMoAcq3pUXXOP0N;&sQi>v_)%Ws-}}R^laE=ZR?R6s zDp9jqxb2AdY{TVKA8KAawNdoL7tz>)sh`fNKdNzmU+}5TSoH8Yf%R_l*k#Tyuz&FC zeb;@VFZ+L}zd!W;X7EEF&&)^pw;z97^~3(R!QF~!zXNw(Eb$d~zw-Xwp5$-3{*i6> zD&8u7RPV4ce0Wzlu|by74qWHT(6BsAJ%$B&U$!H=FvXY zkXK((o@8&FT515wgFZ^{?(L#>! z->?61Zv5Eo;4k^(@;Cm!^Kxt~AN${Q{>QodgZQ_Kzq3r`Z*hC=+_NWM^52zRYK<$R z|G581Ui8YWU%j=o>__^8Sp5UL)*q=fx%qCZF8}d=*0T@KS~KnYuG+gx;`3)Fs~*v} zee^T+(kY`kuRF66e@Jut-*D&edAMgcf7rCd&clJ<){FA2*FJV$|KXk40w1;*SUjDY zR$3r2=TNV@j{b=U8%jTMKG|a&mn}Z)!oy!P?~5nx?NjHMu`8UL{5V{Hsh9DgfJ1)U zGG3 z(#xxW>e;@ zqkFhhSKTy`YHdEBTAW{~ug5L!E!(=Zd(kSlsj2F$VK!5Bxh60B`S7f|U(AK9kSABY z^6#wXDpj_Swb-NUBU|3STB~Tqiig?usdg1B9(|Z%IAyw#r=^xfSIxC&yn z{h#5HhWrop_`kyOx0nBC5R^V{|7UuvyFvYt0Q(Pq`+uqJ-|qiU$-J-rr(T1}miQl* z+y8MsUYBiU*O~j_`L}0%ucNM(+?Bif&o!opZfIb=bH0+rwTS5J}f#b`NPaIsfsxx78MUbN(&|9dlEPfhKcORiq- z-h4gc)TQosOV({GOS)iu($3-!%Mab(-ha%m?c@Jy_?js&Txa zW8?jBuhVPSE4f>1mEP5w2exIn-kZ7dR&;#CT{odex1Nbik_>3dmfBGz`YJK&+ETxz zK4QwRBO=df1ug9OX1d|rTC>Yfr)>Dq<0e-XRib@uv8h&Rx@5NB)~LX>Ql;t~k2I}B zAB$bd4k}(Ae)CG-s>0r=kkyW!c3xLjhPCT@70jvr&%jfWes~_&hx_e+WFP!xcmJ@x zWsmxz%s8nJ``c=4mq%s%;%~39U3lZ*vW#7Fol9=Gvi411^3tkw?cTPz%WpdJE}c3@ z;CA#;8AB!gGJWyRTUIr~mlRR^Fy~+!> z-1(>QKf^)0E&jZJB>porFRg#Dn)%zzD_`z&{K@%o{=;Us>-DMJ{o*#aRQDe_-~3N` z{|C9nE02D7_Mahm)@jd=W-FIe)E|_SxUeqg%ZgIolPtBKcf*Wd zbuu5X@og#C`Z-3vqhe2<{p43)jbqGQXB4W-r|pPz|2u1*nWU+YUE!gvpIJSRv-0@X z$woZyJfgE(Q0nna$B+4J$x16PpERsdZjH!1RpIUzsouikLpMByFRU3%-{Y`;E%zFu$k3*+gJZs{zz`^!yoz!woJS4 z+8vmY|7=5K&a~V)4~u$~o-KPCx2|yZ$zzu8d{2Kwd9Blyp7mJeN^HjGhc6x)^@v~F zyym!Q&%p}^Q?J(UNtgNTX|q`E=(8UyJa;(FwOOyTG&Akyx8&}rUJ*QO;Y~%Ms(yR3 zLgTc}j%Z2RMYe;^&-r+zc8=!xFJ3D^YozV}U-{=Kl-_&i6*0 zKb$XElkmg#!{tYPdq3nK{kC7gPB`1n{)2yeP4vndvyW#d-}X*_^qwW|^{(14|D-;O zF8LN_Zgy+mgm2p~#NLRAb=A5P8FiMi-J5g9#j_tyCVq}F<2F29@N=r@n~ztF{@fGE zd^STWVnx(e8@)sxTaL#XPFeF*0~fzd)=y=69tO%|x+^XH^^aaV{Kzmu^WVK3J!B zajQOG#ri{XIv2OR7yJ=_r0mV!zvugwt^XO^wi!B4$y*t=R?FnWrH`i8?^V(XA zqh4#C>Tw_c&#*!Kjp4`WM`yPmpWnHE%9yYHJ z7yPu*~wTz~C7hy7Z;sPD^tf4e+nm;D$#&#K4Z$I0`ePIJZETD3k+ zjVe5BSN36*aZ!9|Ua9n9lNaVeOJDx`RC8Bs<8O(&6Y~^)yj}9|iq-Qshd=O#{ayS; zQ|I|5JL@cY&Klm*k6DMF`(EbjUKZ#0_+^RvM}xhWz7(0P)%&_tZ1?3YPx?-ss;#tT0CgW%1@S8jwbHExzSYR&PR!K9oxJr zqbVsHjVf+Q#F!cW&F60nQEpn?@%O8ZiouQcp2NY14=tLt*q^s2U%Y*}uak&j?xRdM z)7vw@>3GGjz)f+6mN{eLR2UeN*_Xdka5QKVt8$5r6nz zpyK$$+V7nTo3~wmZ^QmbH`ssI)f(O6)d!bnzN|OvEzVRuxp7ma#K~;t#fMKmG&J2f zBkjYFJ#In~Tt8;n?_M9yYLTRQp4)1}(>W`=rs<1&h1{7FE0dCKhe7^->sXy8h(wOSuqCI_zeTgzh`aW-<*jvCwO&leUwy!yxCN96WAyQ?6^KGKT_Ym&*;)S6ML~A(#P%OF4crTlox*SJ>s|D^z{|xF&d0G*&)bjF* zIVz9!*dN%xx%}Iv?sT2dz7OJWZhkO-Xnr7`_0_Da$2(2qx&J7BU~l~=_hQ!ej&*Bu zb@WW%M*Dx*HgoCiS5;TGN!86?zHMdQbn*K)f7SMO?D(xZb&KcSaPhA7?wsxGJJ(0^ zH!iiZ&=So$S5h!#RoFbGwKk@fo`-s}9%)@Y5*qSYK09uy*Hz0`e#MrL-KJ=Ttd%MZ z&DPM`Dirg%*W{|jsd(XDyUI^)e>N7+?(!=x`u6HMtoI8qgFnUh+B5v)sJkS`{hy(= z@V8@)(vSR)+aLbCRQln^9)~v38CxK6%#%$YUm-9pTw|LzN`%T|=KH4u_cXt1#?+5rB<|%$W z6L7oYaP$w`5B&$`^Of2QM&6Fu`*z#>Rrh}QJ6%fOby@el>ZDKieae5ci2Gd^jMh1_ z>#pUwKGB4gejy*`Tv_(vCwAaq#%B;yp%zKWV zH#)k#^Ndz?xlNwpt{W?DLLMdD?m;{E)MtKX2Gp_Nr2Kr+NC~esh*fT3kAsq`AImtB3!dkNGWoG#|g` z{?UF=&g#SY_CJ{q_KRoSn%-^`{*YfR<5qdcAN@!5{MlxcZe;!9?goq=*|l-smRZr+GgRB$-A?W0vX~XLxMQi`R?QtdgI9B$<2_Wk(l2JyaeL&6_p{g7rK>d1uc5= zcaBzQuSV#qg&%%rZCL0en)NzpiN>X#=c-;@Hd(zA*H(7)YGv)s2wobrsU(xO*h zz3TRzmzHW>UG6t;Ld)y0IY~>yiYET{uR9yhy+8YXlbz|`x&KU^AFY1h8ZY?xl8#O3 zq6+6@|FnKoulOqo91@kce6^|BxRnmT{m>YyoqC-v-F7`0ZbVnyIeE90Yy+7F(_P1$KEl9`nF=CwC}Xzb;c zR(>IAUwgeowJxldytq1O&fn>Wf3dYb^ksMXu)Xz5uKwYDQXj5OT=qgv_QSu<Gh<=aG=9QD0w&&MsaVwiUFzVsc*aoHDDLD?=+?MR>_Ks%ehJ($|`d#+2*!4p%ncTZ19S5 zT!M^Grpq(zV~?xJ-0*ktyMF>TW;_2bFj>!X^22SPAJ+>X?C1CW=@85lwIImbbeRh3S&EjvTTg%%gAJQp0w7orY{^rR3jeqZ7pDNx~ za!r5o^xG@;$noAbt^XP1_X*cn{jIfAl{% zPyXZmR=rYLz4|RLt9oXMcjlPtTK{(U-SPL|{F)8Accx3q@(ttnf{adoNJmSmMHS(lcEna#EEGPe_|k^bTNf%|}!{Gs)Y`*~`Z zKU6=Q-`4v6kMe&8{(q7c-cBFvo42H0dB4uo*Du!k@IL7cmrGVh_XdaT*>ly@dd6C@ z$AMSY>uu$}skUe5y!7`+9vfENyu7mK$n_)VrgBL{8Lba1jg`?8o09Qx!lKFZaks^{ovTnY=R0%dk|-_PJfeF_}xbE1U$v zdJ-jm`4&rIBm~CK*N@-7ss1hM@2W37-(37H=Ax-S@4vJ4o8KR-Z;0aCS~06{=h7OPAE^)Sw|%R6 zwrIlfyjg8K*g4O;5CFVio`a;j9|O083KL^Itdg;s`dDe!y6 zS9S8BZHWG1d?3z%vReXbu{IZJfW7l_ygkLV!%Ji0j{nxAcS zbwWPeSn)6`$##yR(V<77?12wouPAkA@0=$8y6)s*p66k6w69LlxV$!;pDR@R;^9+k z7Hkw<;j~Y#bj5{lTQ%JU+lzZ@_nO;@e@pq#(6p=mpheHvEj^=0EtbQGI;L+;KtHWA3ueWjuAG!WbY^{!+)SSnD6+Nz2MRUDG60Iimth(Bw zFy~?Ax(wyB^R!ycrh4v*xvJ=9w3_qMa;>dtD=#hQ+A5NHsx-^u@=}SDyCzRjW>wc% z{3UItUjw$S?nukM;Qa^W9Ap3g3MmN%bVp*-&-#O*ruToS{%3g8za+j!`tsTu@88k? zF3D-;J&I{qT9Y*VDFDE!+5Te`6j0kHC-8 z2j($<$Zx6-mg?Bm zN?!eU{p_otUspNOe(X%ndc4s8wa7=~sWRKVwn?>0JV@-BmpUUMai;&%O?%R^`xg2e zoPX>Uy79u{B=re@ZT(yA-<&vOAJ5&JkK3vK*4tkE_W zCJ+18YzVFBOtYL@`NU+S#NOgPN)O+JId&gPnx?P#$VPw5YPY3XlaGG*XSFZA@3cXQ zq20B)7CVv*Z)nX>^=A#*Cwbx6hkyF~t*2va9&@++TeG_51=jRTvEaWf`*itR><`yB z*gtq=|3lON&HCStKk5%}_!IPZ=|0iAGyiP%Fz*HR7JlM+$!IK3=v@{$kRmZ6DcIF8Jej&9qv5_ocPG;apmh%Q-)`1-tX|zs>3H z`?LP0;MX#P&+zx)kb)L2L;9=&uTJ9o; zB6$8YG=7eJq#Cb#wt}C3%7aSf)9!7beb_}mhP=M8+J4RMq#x_Wdya)qv$C+!DmcB# zXSQ(Xkt>xh>AyrD{Ac)~wEvH={loijColMSub!_yji0;5`tRZz^YXP>x573*@XbD2 zC;UN2PWdBS>#B0GoqwTxl{L+uMSNH0LI=)Vc z^jSK|U6yC(Z;Rv)UkfJn#(!Jda`<|ymg$S9^CQ2l*I63Q@0l2@!+rSD^0w8T3*AIk zKKdBAF0E$g9)k_X4^53j&@i+gPrwI1U;BGk%cI@#1vOt>axa$?G%YBtJZx zvVHrsU!}9NqMmInO+7p?CMzzrn|f_km2lDv@>p@GIJmH9$;zO$9V;Hq4tbHd(r=&A zmbV{*7CO!Ky1L5i!cs5cm1YYiy=+;xp56O&@7||#kC>ND4>($!U7D-qpI@ABrL!R> z`mC@?u(L_tCRd%DlS)Rr41>5cHBJdlQI~WonB4PF<*~*oy-Pid-aOXWa@jZ5R(7j# z%i|!!IjWL}3WHl7Tv=>!GR~-H>XpSRmwl~G-mPC~>gni!(Q0J~0F5kQbZyxGU&UR} z^JO3TXZ)eQDd+81e#sx}561~!e)q0*>e}y}U+?NWY~HyyW9i&n-FKzYt3A|qWhBl@ zWXZcUW6?B+R>7I6r?di_r-VFNs&R1ZS&hTf=LPn?b)RK(R$DLQ-gQ@vlgEMsC%4Fi zJe&NqdG;2OrD>CAhjrx^o2FLF`2W#=-zfhj>Yq^k!{ZJ1HNSM_XGF8V*6X>|0w(;{h#6VEQS|0<{!NuPVd>ucBw`YR0?Zf4Z7uh z{j!buqxbx;XEjA0`si+YJ2JDX_3EkHt|}jntGpHHl*^bn$D~7Qin_+R!j`2RMW0W) z?l?U2mdz*66`yUD%hr7fPuY1$&v43ON#Cs;+a}KrEXvZ{^5ja=lPkeln%h%m-n}vf z8m#p!_dgWzcbV3A$bX2h|Dm-1fNbg7B_G(@AI0B1eB_$gKBqfgrTN|e8Mc10llVCK z&f)Us5qF~RX4-S_QD-Up6!o?+zhJvs##0yHJ*J1t7g-j)Xrm%=E;j|Y`G^kRn`4wSpSyki;vyVvH#-~qZ`Wp_Ond6{6j<2 zRE<;me4FY77kbUftTws4^lOi=UuD>wEUQyoQ&m0B?f-6ne?H}x) z|H18j?<~Q^Vq5L`U|`~JzJ1#Z=FK5>4SUx;*sV$tF0cdxy`Hb+xyayCzA0@={HMVrR@It zC(d~I^7^;3*{k!DO|5c+`@e6FO;^C4p0Or!Vg(tW-xvL-Q)Bu={KMm8@#6aoe%wDi zpZA}{AG-_h{&+sNm;SLmc>5(A`-g9(PVig3`}ghXRA*1+quJ@%0@FSR?3;Jnf5Wz2 z`*v;LHox8I%m+(1p@=)jg?Y^6Of>?6Ce8Jly3u0Smk&E^)TCN9uB`7q_P8)~#Y2M# z9aF6vYtpo~>X=FOMt#jZ6l>ulr!E^Ok)x^}wdHY8&B|kfty(6_;|1fkM)jGjNZfEm z^XieLLeu435;?Y7TVG#U?l$MS{O8C28JeEfg#WnwpMh2T!}i1WKXm&42tWT8`{U+^ z=?}jD5q=#s@3iaR9e>hSWZYx;c>Fjo+x16&lm1D5Tz~LCL$iMNii-OoKY~A$ALm^4 zdjE$FHm;S+qr3fOD;6D&_|UuNp5(`^)7v+8pRX{sKfPnVs9PjY#boZOPd^;;7Hm11 zG^OxMvBuM#ZPiWR_6MK-V0lhlRHm&W#>F_YFizP1;jO~uHeGsa>t1@RJo+bh#=@FE zPR3#eX6%zBlD>t(V_pxmfw|(v1HM z5;oG=%TBJ1dntCw(_~tec+VE!@WcOXFMN5nV^6NM-$xfKk?Ys5M};1}@}D95h-IBL zZ!qJGr&m^8JZ1bw_{^qPqOY9R=E$pQ3r~Oi>DN}pu+5VWrbXz)>ZnFtYSR{Sj`W7dC$TatCQ_HTI>OY5jc?b+O8c*AN#pSt#$m0l4svR3Ow8`pZx zvx|rlJaFOMho9TxTjxeq$Q6H`wy)wlct0=m(fW+}H?Kcf|2FkQ^6~kbufG+1z^neK z{^0q}s?>dxAN#YsHkX<^b=lhN)RmFhRwWl+Mah1fzAod}vdL>+?kd~3I6F#h`SNTj zyS0hwD>J8G+rDkXxj8rHsPd#_9@`RKlI<+$v_xI2RO5Qnl;p6f9u}vJ0_QwbU6U0& z*DF-nDpZ}bG|_NI4{v^c+ni)OuPIBG`_0WN)eLK19yT?~bg@-v=9QK?sazALl`_1of)?hjb5tuJ5w zN_Rnx!N;eIqJQ*1+`7qoRqm!OmlQs%@A%_fn!bF0-#)|px1A01I@2ZpN_n*zN%*N9 z2wW^xk?~m5nSb6xQ5);Ueik*SL_b_OcA+IB;lmA?b?cP1Pkp)-c=S=IPHc_4N>PQ( zw9Q2aFT_}O%=x?2|IL4f%wU}(*H>E^9Zf2LZ(!Tqqje8&9E$Nz}l{+9e>>wgB8oqrc>)$E(Sw4(o!Y3uX8`qcFu z+Y4-4%%%Dd|7YmCC$VYgC24O@Q)$oA+Mq|W!4Lm4w4C|RkZ`q5v(jshNSNS0?XVY*~ROw;<_WD!+3;mWQg)hX zfx+Uypnq*PypPW_|MCCO-~Lab#`NR#);h%s{-e86w{3qIFI^#j#LB(fM)gsw)K`{m zRofaL*|L2OxcGIh*()QJZTl{-*V9dN-eno-VQR5PO`Ex6b<44bs~>y}QF$26+qpQX zwJJFJ*ix;Hy&j%+lfvKU3U1Zfvf6!KuSaOVarYFJB~uo?)vz|tJo-{&x0k-#`r_4~ zVIPJ$MHS4G{Ih0y8T2f-bQ5TaS!!u2am+A$%2M@|MU!^t-qejgHn19Q^o;)M))bm+uSmg9?+qnK`V4eSQ`*C~b8uuSp|1+?B_#ye> z^`rVXvp+~bOk4la`|YF0(iIwO3|4 z^UUj~KFyji*T+q}N4@P>=;`b<8*`^#v!xTSoK57}taH{_GEsT%<9TY5rJN5pgccTm zEXw*){KhYETI$7BpJUGRHyue{ne@E%^oAN;omwf2IcD6Q8-M)qkr2NXGl9QRg>!9eEmNI%bxTPyC3=dXW*$R ze`xa2{Eyl{(LGnB9WK@QF3J8U@Uilujb&kV^2(P|N91ownJry(Gi#shm4&lTJ^adT zsbiY`pTS+U;hTkwS|X=?YUj~3%UZACxl)rC_nx*}ZR3)8_3+iz-lDB@dFuF<@}$_# zwYsX>x!g@uy+iKM-z%YlM`EJed{vSc$6Hh zf7D&DWu<(kn|%1({N&EH@vJR>C#^TZzNj49p|r<)LDQuD+52z!fAjjg=a2Hkc*cL% z?OAOsKW;x%$MI2Tp23G@{f~5=kIYJ`GVgeHX}yW(R_*Nd+^?&6KhNB9`uFP0+&sNy zn$b1B&WDJo8F%cGtqi7_bGIFR@Zm>$eWo{e|LUf-J&WZl^}N0oz2Ws- zE@_uzYBne5=Pt#rBhI|h?4YZeL^u5Cx{@m{dHs;HAdhW$$*s8>NgoY*7F~Y2K1lDC z&kx~$if8{bG->{4xY$%<_@Cj>_D9eEGuTAEvOJ7KhQa=k%>5rq^Z!byAC~{4U8h(7 z`RD@v#r3J{f2gSc5ib9x`D59BY5UasH~kO%XW-bUdHmto^h1Fa$6c@eDPQ$U;79cl zp@@@fGC$n@G5_eSXLI>)_s!0j6nivf`bnnKxxA;M@5Z|8`^u!L^Sev7FATlBw12Tb ze@{6Xxw)-MlugC+q6zkHSYE zJlDR@-#JfMv~g}$S!VHR&fcSm@2>1Gk6RR$_xz=7v8*Dbo5cR}*MEkC2a_)Q|7U2P zx&J}`uim4t4-4;qV`_RkE`Gp?i39pl4 z(qDbtqbSd{X;1J~qF__^eb!3hI)jNM%tv*%k`f%j2h;rCIdG40Q zaZ6r2F!;FiUt{R8O81|?>knT3CjM*rAF3u=3V zr+|Ch&|E+*>Yv(wh6mf~1^0yhXJEDe&(L(X?r8l7XMLU@vtuvXr`L18x+nkR{O`ou z6;P{`L;%XMNRb157&0<&HHdZH}_$Gi{>%n{`3XPDTi18=39Z+)G4-i2xM5{<+&<^Q$BLZe){l6)n>Pv_ zIJ7LW;n3-h#cf9}Ebcv{+Wz{{9#@~{mQ6KmLR$)EK9@_-jt8GuH|KX#SS{ar>Kxl@Hc) zN7M*j-N*H#`N5t2{0lBWxNIZ6yvAhLhtTWI$6MEKIW6(1+4sZW_O=_D+pb*;JhIKq z;Mlfq!B(?MnaX(KIVmxbeP;}(F7H43^yj|RaO0J6Yju2WP6n>+TRwA5D7(}b!-$+5 z#oncz3pK7SjGLn!I3>$TNV|1qz^P)MZvMtYmw&Aj7H?eW&-~_L+|(TVZOi?Z39Z#} zo@*0o6RPRgr!-IXN}HBw)?wkd%3;gxKPmoaVDr53%5488`?nia`aZvu|8Ut(eB;Jl zU70GE^-QJZ+p03J${n#gdhgoyD4WT?PmZcw`xNnWrr;v=yVq9xt!FLxGDX&E(<42t z)mEhni{s{6&GcurDp;L;^O)C`O3NjSO@prOF8W#d&~EARJ;7}ebL@;HawfNZn0WNT zYQJslqF-~K_paRI$5-5I>CYcqbaio5NT%Of$)Mt{rvdHXj>lV7CqnWvqk~-b$KnU) z583zcW4Tr*{-@wa>I3`k`+PO7QpeZ+kbmUfYT_?h5gqiY?}h5li>AM2oer*Bt8(O9 zcoXZcjXOhjZkZ+B;;B7bxcSgyWsam3!E08YGtIO-et&V8P|)(IR@c)(tyx7~Q?0Hn z=bA7jWTC3cobrX8M-o#tAHF&_c}}cVm;RmAUh%S8SMI*Nw%By3mua$AsB*A7W z-v4K4>iBp3Kf|Wye+2ITuKw2ZpP{Ly{$R*f`yXoIM`R0Pe{8eAk$rsEy`8_^Yj}VB zt?T676`2{&pz1GO<8xtl2%X(Rw)0?{vV3V|A>Tty8*g$rSAMbr61kDQ|gZHTK?u}^}~-3MLwt>`H@@W`7ocU z?qZqM-+5~*SN`ZfV9&RwTx6f|hj0B4f9RUHPmcX}|6_hjjlX)w^nZe9OI0sz^)APz4v7--DowgLq zY!;8_588fhMfky|n-;f6?7yS+fxqODo!XD|xR1*Z*LT?Qec0YL|G+-AkLgV|;ScBY z{kWxTSh~_ie%4YQ4H|&8+OKsH*#>3$~hHYYHxyXD^UC zwRlgv)yWmfsnf2V-L$4I+TWm6;*omOG;8i~o{a$uH81x@27H@$$>eDem!DZt_?}vu z>9Wo`=Zxl@7H*07V;4U&q44Slz4aR-PFeVbYJDwOw|Qw~P((*?$y|50_3Gy4o96CR z{p0+f;o#YM@|*wm?SC+3{s*7+KUB&O&h>kLR8IBd^xl0kKluH-PW$-k2mYA8sP6nf z?hPN#ep_6*IQnj!^YT}AHa`x26hClJGh4W_%6^;JGmCe5y}R#(ubp+dPN8D!VavGq z=Eyw3M_EZmD;{mux>^up9WM1@kNCl#b;*5`rWs4OEu4_N`Ht~Xf6mxbmOdLx7xMTN zd{}*SvR6NAMd8uNW$B%#Ul#|p$(ya0QBxAlT6N=2xJ;p0;l!sUA0yU;nzo2&Oc=bL}bEPpiDC}Y~tNUcl zz5Sw(4eq$kN;6&RRdiZCXqvG0q43pVTQ*plMM_2Zw6pr{jhbr6`!upnn7RFMl4?}M zjMKb+yVvSCeOump=*q{RX0cO4)^@D;ysBhHvaw9|lW$u;cWvm6sZ$E<3R%qgDAwch zVJB|R_Cu>GbZj*eUIs1Yd;Kl*@8tby=WjfI_+~#>ed_t9dkjCMKm2+fyYHjh!iVeI ze~Iqv&tCmwdQj83OW%)3Jw5Tcl(#%;)^WefCHLRjCVl$$O;_9JvdM~cUu(Zj+nf8g z8H;u~TfL^P_J6!KYRRjsQ(pNMPtP&< zl6iG~oPgIhwZN%aeea5&>{k(2T(#(AN*&X3bb*eZXy=(B?@cnn@eCT$+9@3=*!Z$8t?NjFND1GW{ z<7?i!yldHtOKbNSe7&Z7Uf5GRbane7->q+ira#^O$9e6-`b$asAMCvUW1iXkKQFb{ zJmde-9_{p>Vad_@gT?zl+T_~*ycEFrpF!YtM*No<>woB#|5NW>{-43hi{aPjZ)*P; znmjV=H~JsTv@?#XKj`?M;lZ-|TaH|+aE|%V{zp6i*70vkx*uIXR50u5x#>ms6!JNo zAK3Fr+ITPh&yd=&CD-$->@>rB_v;sXeOi3!)ON0o_dI^l=5H1| zKApau_-LcQpj3G4#u9_AJLhil zvVVj>(&iWYWAS74gZumypAW_!vkz`ugj&f>*Y#)ymq+HDPVrkxO-ddE$fxeNRnOXYX04Rk21+ zt7oaZXzOZkLARi#VM2D<8fR8M`oSGL;;e|X>jPw>b7qyHI1b8AdWJRP^V(S!CC-D52Az?Lx%#cODLVzH(}PQR$f!=nM!| zse0*u93K|_J6r#uBK+ul@jscnW;R z%^b%n=E!KJRjMV=ORaJESP{cDW#f()!J%3g+jOh>R|P$kQ(E?+VvihK$%ny z@iVn%?7Cr}@#&4rtLn@Iqn>kp{9T()BxGFqR(F`2CuHMJKfQI5SEg@0yJJzC;yKY` zEsM&3*Xj@E@6U^s|0epMp{epu{>Qx8tM2yq?U&eNyrzcn?+hE|hdw%ESUR3rDn%z5V>rD}Kiuga>5ZGC_KqpIbzEgNc7TNig8 zef(p;z^06c1|=VZk9cdZda(J{sS2&o?1%B+a=mu&@aa!8_;>HjrWmf({(}97PkgT^ z+b6Ge^n91$r-Q+#D}uDG*V~+nnORyB$30tcTI!G8Nd}WwI!pH~lwW^oVdvtG<&y)> z7JgXiH;rv;R=nDOhJ)Js)6c5^O?VOsdnuQs z9kcL}h&{{ZNllGWvzMRo&{8|8cA3)tlU4iwi1YvBGXHH}cjrF?&;CUFTioA5et?b; zt^B*nKFy!?PudT`5B1-|nvcozm;PsH-Y>pS;nhClT=NI_kFS^i@uewV(^XRkQ@i2rE6Ty#y^hw?W0BdS~P z`u%>Get4~S^rTCN&grTjy8NT*;#vo@SDym>6XeaXtS8!sPZJ~EV;<7c+|bYlBi>*9(>AMR+*{#Yi| zqjB-1v5lxrT4>i?pHTOyj|*-dv%B)yMpw$@>8uL}p4?bjq{Dx8qr_4vlSzxCBIc-n znI1Wdl|h8@r{nL6`h!{fAIy*c;GezHM*d^{W2TDtkGGyZx^MQw_c!|=gifg!t+V^l z9Dl`T>%~2G|9CIzD{uZ#w{YEA9kE|J^94)yv)#e#8CYKi3u(=uP^E-c!4`06x9zjc{bqMfc^`9M60A;3{X{XR{wvDqnCvteL-Hy8E6T z7xfc=I6ltj%Hp)yrGAuOERvD+`m#+~rkN){ie+{z_FHPQbW*|B%8SQ*L;9qGmv)?6 zxvRA3+d`XItB5Yx4g)gJ%dTBe3YN5ZEWCL}g5 z?3x<+JBzpI$fMP5D|=_Ho%Kj7Ep%4Xlx)k|un)bW{NEz|R;^mO$5!*%;>8 zGo-Ed(p*`0@w((S5rzQv52t@u@&Bk0|0BEbx4^$M7r4)6KfM1&_n|yO^Tw4y%QUsP(-G;WsVaSB(y z)o35I(e>LWWm^2_Sj4MWt&-u#ES~M`NuT@V=A5^k3tJ99`k~zPyz5YPlttFYwxU-- zM}F6o#jUI_4po_PPx+%<gk67J(yKna5j3~bD zRI{aPvaPl)E>{WLCY3gG`R$mv`}gjgmfgE{jnH|MPMMt3r~8gQG`b_FZE!riO`5go zFlfoWsC2+$rxsbSt*R-v16!iEge=uvEa|yo_QQf5J$dT<&4&V4b{tK5ed%!GilBZ| zudA=m1}*lQ6Moccs;Y!*Y2ID`=dZsN{AXyI{qMH@htT~pe;hvY{}Hx+c>Q30Q~ZYi z42Rx}zN%yY&(L=6@5UO=kLr))Hh=tnw92dg$f?^8{NH?jAm1^c?W;FGZ)UFQ+^g@q zY-&GpT}$6^WzCwj3nlg9hu8f`cDT&#Zq&!Mta$FF<&#stuDrH(^3zwMhBucbw=X^^ zHRDZm%Zm#K9%ek!Op}nh@*&&!+m1c9772wnR&CjwqZci4>u0S@&8C`7TZ-qT356uj zNfXIlW$70kw^ib5WG<(b@!G!QyGlRom~o{(Y|(~GbF;QAY&nuDap(T^`Uma%KZM-x zi2o46-zL9h-};Z*2lw$_Ha&lH_qWcE@&~Q;JLUOmY#-Y*|4@D`-~Q%dt^47BrW=0b zK7N~jOitrR_L@5xZ_^9cSLla+yx+a<%SuyevsvFRF8?i5C6T}CnT_`08voXy!#bZ# zS6)5+DrrS>s?$1Y-4mZVA89@+_^{M3BFF#R^^FVtv^Mo$d383~P;1qbXJ<6hB-JGf z{n^tdE)Nzz9Qv4R#x9YiUOjhxuG^k^+Vam#ZEn^NubDEhLXTWpD-qVF*Buch*pnLm zoo%PDQv;6PAZfdRpVkyV$Y-nZ{gB^PC;P|k!}9i;(g*s|FRYfg?n!=dUhKs;IfW1V zyK2nWMV?;%T8eM~!dKJ2N0qHz@~X`EY-Vj@b*}B!vwJqV>g4n|CwCmacr<9LjH_wT zoH?p#w+iQK9$Txm<+-@zrL}HrG_Ng;nzJ~pH6wVfSK&&Ib5?d}VFzn!5Ayo0q?}&0b!kwt05=zWD*y`hMBFQ9VIWEist&5`c$>* zT$gM+veSO;#pB5z4c1$RuQmB7ai=yXsHo{!_?dz)8VMV3tV{1$-_pLR)oY#HIg1$& z<}96__|YUewS9f-p@5Z61`EBWEOzH^Zj*m+e`EPKw!f4AGd!4A&-Ltw{cp8DYM1Jy zDw2b*%#QmQwk*HYU+~B6v|fhHGks4ZRTxjdt6(zclo zU-PPaMZ8J+@=@Z}))x;qtTNf~Lr1FcP(s0$#q9?l{#@ub)oa3H?v+VemkvLCdHrbU z)R@q!iW*z1tFN3|B@WNM^liqSyv)wk(bBV?1&12*T$T)cWccHzTWQwu*Ag>-e`?82 zGBmwvvEtINW7^`K1;38z3x=(~vGqh2ReK9i!)m&JC;mHRziIi~mk)B;57=+jKa^|! z$ZYn5{|o}r726L){oS_lkv&_Df496nXD_|mU);@q7f*Oa;2S9@1H(y9#>pMK@(`svAgCm(yDef-vgk4B4D9h>s% zV*d17mzQ@Ox!9UfbgfTbwEJ+i|LR8@MOOX!{h|IJr|@sN8qFU!ADq8s9_Qb8e@ptY z^KD}0xAG6^%m2Gxzoq}!`djURKWsBsdS{z{uF<>v&)~=DBe&$6OEs5n+EP*a*VsE= z;6|mY$=RT@dU{8XFKs>Q&#IFeqiZE%IJ1@GVd2gx8bOisl({96R_@W+cxQgZa;K#_ zX?nd`A?aSGFOoJ|RNeWaeRZiGkDJsyJ&7!dzN{TKvK5aCc5r&`;pOpB^(%ROocDv* zQq7BpuP%LSyF~N);Y34|D}@#@wh?u`pgr=!AD_2>mFN8N{IHzt$N8d;p8wKjh8 z!p%p5s}AiGmTX_$dMq*9`QhsJqYtyg4ku;!dQGjdjoOlRsN}hY_fNh53{B21^S6cn zkzxJMz&hve-uH@o_J3G^z#GW*B%QS^CxYD!7(tn&|)vw3n; zd#9a$noj6(c1ED^VHD5Y_}~R1P*9Cth>GI&iw7=e`F5-R<2>VBJZ;Sber*m ziS`_(^0(O^uiO8~dh(J?EAgJKvG#}Ug>t^GT>nl*s`T3Y#QOgXJa?Z;PtO0wq44qQ zn@xL{wjK(L5$}sk(>`)vu<+}ur#Hj7QnvnZXYW|+%-eD3(dx9BYRTfglN*K5Yx#cI4Rk+xXPB85=&lCv)!O4)&ndtetN9b|(!a z&(=&Aj^~aRY+c`TO11Cb`D3AnL#Ik6ZTK3Zo7S&o(PNtvSLn_jCviqDe13YQoV?Le zt}7pYF8?N%+Hq>5#UE80S1r?NeA~=9JNtxI_pD6%@L_51p{r|Kjy!yI{?)8!rgr&% z*VU(|{asU^-rw<`Ve^9@r$5erz)~;xW=pQs^GEyN{CxD}gZk0^yf-uFsa*W}`*l9| zk7eGxz9lF2xMwao`>bJL70Imv6Ky@n0m$5S64OIVq_*lBL%wGhomnc?f5<}8*- z)(j2`K9m%)*wn^0R4?;#=CR;b`%I}RS6=$>*E^$?I`!2f&45GKSKII{nprp{cYO+px^$3fBz4)uRZ4W zo81rCGF^V;Gp#>&?VpMtP0t_6AGa581@<_LeBURz;o8~Ot@qYG%y0j8 zkMBe1wFPZ|ZH!q@pH%*Rb+gy!1sf`&B62n}EPOMKU3cl%ETbi>LRNEC%vx7!IOE5~ zsgbMr4UZnU6O}_L-jBrmcJEIA?3!rNYG$!3Qs# zUU7Arly2hluES4%R3v01rTX6vIvje`$#|c+xYd7#;>#L;wEi%sPp_rz z4^EUlTXS7#RZ%31VbGJ)PmkR6K6du(A;XoP*VayQ3yS*pyK`kqi6U>P*VfES(|4Oa z{!(N5cAC1$G_h%7`;2TXkJufWW_Y1j+^sT9ZCY-azF<_V{n|t$&1W<2F!el*tN3Fl zCJ|-P1 zr|_e)JLqmKq5LIt7q!K2^Z&?vWS*+|g&0?vZ|2#0^K}AES9aQmJbvjkT{wBehV@)O zcvkaHON~s^vO8r`7-<$h^`Sv!TC!hAqFb+5ob(Xq`W(6Kf{18%5k$IZ8 zeaZP1_UZAr`M;(9U9wNH?t(p!eY(APRK>sd-|{||^*)sEzNh&izr9rbM|9>#^&{KL zZ*5!pU@!Nh*nRWm8~@}#?&opLFXZ!pC?dykE@MeG;E((+f>!*o@pl2q{St4%(UVzEt3k>I5juxKZ9@g ze}>fKYgj8CA3tyIvlsRfRg79EW_%>{Q1J2@pDew(dsgb`#`%~jPus34wK3DLO-W?m zmX#{FR%P)2zxa>rb9`_a%7m-CKuE)sMN7pcwU2ooUH5Xe>1T(U?%xXk4$a^6{*B_p z^__M?f2Y?;%ePzUAHCldr|{$SM>fkp!H@YR;(jzgV((nLM(3+;kZCg|*=5(uSJmfTI;6e(t<$4d1tKq>&SdBRaExt^!B2gj)DNePYE+cwta!Nc z&|Hnvf}N8p*3@a=2soU$wD)+}k)-FXhY}4wt=Edk3TWH$Yx9}SYi@TK&e>|5^KSQ% zG>aLBOs;123w9liGRgdOaj|bw;f+%lmwE}bsCTSbG{sU`UhMB;`v;TkH~7De{J1^f z@4|g1HBwi%)_29Je2DA(aQ~6q%7^*g@e=!_U&M?5ldUKY+j{LwJyT7_hxo($<$gpT zyf0Rx$+mF$%l%mw|CBF$J?+=N`Aai?>1{FP6?eN-@>}P_juJH0L)XS_jodXgJ9M=< zXftuqlvg2hmTI2!3(DPg4s;^*ionB(D=r^?_~FaS3k#ikEiNr~>ebLHS#fD8%R;}o z7H$U1{W#qOx_W{oj9>8`dn_O6>IYo-40A4RnMdaFcV`i3lx>WwPu^$N|r(lys=!jyE*qh3b7>hh;}_5X3?{%2r$ z`QcyV+6wN&atuG7KICtXQ@&<8H$Ud@+&|L4Q~%xAC-`@csr7onc<+@JP3N9JaBsJ> zdRfoo-~M&=>CW519~M>Q+US?(n(WG%WqIkw&9DzWp*p%;Cm&}#n3CMObjHp!gGGzO zLN7f%R+|{wzirN|bEa1#uFmzEwEAt#^D}$*dOUiaykTwXjWaGUL)UhmO5|C!<<-T- zeyvugDr*YX^;QHf_L`#|@U1lQ%|orCo=3~-rq(F^F#Rz30sG;<><|49ylzQ66;FW<$3 zy^TvBZJeEZM_P~6{if>Jst4tH^~tq}Xe6#U{%~>oLSL;Cji7+VZnFZGa~#w- z-p${7_@Sa!MV7&0sj2Ew%ay*by1wdt*xt(SR?YjHTZ`CjN&2y}qTfTkSe}>ZQ_n&z>urh#02;>Yu=6~z^JFkwxed*bc zj~|~u*xyv}x>qS<)1T-ciy!p2eSFO?_E;-3|FLYjYpmm9j$^J{GQDzh4 zdB<;E{&r_o-RXIDmnUwU@>BopsXHlC)?6;kUcP(P;;4|Nu|ca|9E#bzX64ySJ#*Je zhHO_!`MG#;=I_(Hp1rPN{OJC0{?S^=8ut&|AE`Iisa8~;;9Ot9eDoH3Pf41N(ZW)H zzE@IHyTuqLupT@iQ?jn}(rRC~P|c8*w8`CbR7F*;UhbZ>**9y}-FmZ+&swuWr9)m_ zUU6-$Q{m+3yhTrQuf1P&@8A2ei!ApB^!rHf_S`;?mM$ zEyvv4TqcvvcVhgtbpj6acwO?==~*eIZM`AD>&$bmf~j7UdlWf#`V~*=Q50FP=@qo8 zCn!93x9YlST82}eN;nx!S*j{=OmnAKP+4GCc%JW;NnUSvYu}YO{Sp1`>fhcy#g8g$ zgdfbmb^TlF$M&8FyQ(GsC_l{ax97HTd{mLYc=EqkT-sEU5xw`?PC z>0<#_R@bH^>o`4IC>h?bZ*MB{YMuYHJ(kmTZ^c~SwzsV3dN#LxdS`w3%Ia#X{|r0l zz7@}lnzL!|Qt{1~0&8pEFLPvJ;!tRCWLIcDq0q;nyioqyWM8vcnak7Wz5G_4wb$;U z+ALp_%i+FRv#L#gEo)t3K+aZrXoj*!+GzQs`rD(w{dOGxuI}T!WGdfhXaD2(hwq2) zv#+s9e{|w&e`Ea?{iFU3o1D|j7vDO&E=x{r`ory=Te$Ou-Iv_R$Sz*WFBJVMFk|Ug z<%A8#SG~$Cee&!_mt-2Z!TIcSdy=OzN*D8bMeQQ;{yh>tIHU#!sO3{v$BG;? zrKvKpQ4v}6)tJiUGE?DK+u0zQU!#2=Ver}A-r`=0P+@vn-0gdh0Fd!27R-}JwIrm{)@ z8NBz;RN54N`JLTzjZ+^*ETr1<=eu4z_fg`^X7z=g3xnnuz4~!RELl?is=4_e1hjTTVL&ovrT<%u(0Lf zEsI&DvhM9|cC9{#w!AWXb#7mlMcgrSI z-{hmW(mS4RzhJe)T-KleSpAKgdsSyV+-M_v{O7yaj+Igd-zwHjS3Fv+V`eqScB<9B z;|6Dos%};&``>rrmi5iQ)^C`j`giMf!yS-5HlC8DuBQH=H|SK# z_20Vw&e)T?vhJ$Y{G+_u57Q6q=dF1CIBsR-hvSdckHj}`FWXRIePEyBuB-W9tKTzJ zbUXDQ5u0YEa3yW)WgAbiwM!0{ZhQPj=jq`;$3@P~i=Fx`#!-Hax9pTBkwyH9_p$Pu@bTc>1qZ<{oC{<`a}@%8NnKh|6~KE0!yZ{=;< zb45KmKNn_No))yxwb=Ec|RoK(+8noespLkgCLEq&g$*y2Bfe*A}&`v<)L+CNBt zyYqKcc5qg?c)Zv@{R-^|@A}P_t6cUhWk0l@KmN!4BeM?fnbLOU+10J_-M?y=-u=>b z{Ov5>Q>#1UUTS~&6DDVw&z@pYnJ6YNI`^4mU!m5=6?1LUyr;WO^PKF}CuOQGqhfG# ztDN3~%e_`#*NX@Gwd$xm{rN?mr(FD5=t`@gLr->w^03Kjb#2q;?>)EC=!~(AoYfXf zMXe2|KmC(Ba;g35hEGq9p4uI>ymKj+{GHUAonN5azS%#`{m;Pi?uX`Ymj4U~-TpIV ztpA~Xzv(|i?){suABMkW{+&{z^LLM(afSRb@%_?&>@y$di@lKFY`Sh^>BIb+hi*T3 zw)hdR)#b<^`442d5B-zBvd5C)gXBe1_G@eSJGa*QRsQi@9AmEM-f*gLo?OAZ^l1-Y zIt%w5O`r1PwRG$HH=lLFW&bl|J)UN^Pg}a}*p)LcA8I}|DS9V=@@0}-v{U=9^)pj< z$ZYHX=BHKs;(YewP5OM`1;|>2dmPy z7VrA;PVte)<%*XVj~Du~220!MDYJUnXZ~k6X!D=p!M*c0*8k(2{yXlE5OMxtuG#U! z?;rhV5X=4^7AADhZf*IxS8LN(MON)hvlgA6DmgD$>(X(ZOY6i!H_n*tv?t@Cp=e>q zN*z1lS2v4SN=;Stv)Gw1PivmkncvWcK!C7eq>i(%RY&|$hNJjyFVqYd~#!*#e+4wJ61ke zojT*x%`cm7MNajxF}nZtI{)NrD-X^%bIjsQ7(a6~fMWLIxQbdlOws5e;xlOaS zR^;_snY;{{$8CLlmBkq~^;e&#)xVwjpMmXi{Xv!g40-Y#KZ^b{9K6rA#r|gU5wmaK zqWatG)as5$)i?cZQ_^z z1he*h-?n{MQqdbXdBZ8oqh*`dI|~L)OKe!VR%`Oox0(L@;k=zKPa9UYuhcwsL%ezZ zwie~C(3e3WJO&kibZhqUP1R8|=j}Qiw7T)QQ}DM9%R__K`U^V?x~)m>?yU-JiNBuQ z-M(>kSVVnt+^Qq)-}=9${9t~_e>3=7`483KrWMRVALTYbnBQp6V>a=*(acTLqNKDzwnwX{joHT`spGq0Xo zPE$8p?Z_<$z_%SezEwBoxcXK7=-Ry2@?2b5 zd{bL|+pn#b=N47;q-hn;zIyHWV?&8I?pje!lh${vSP|sA$|TgvD=6UE^qtpdm9;|J z&8!R++mG+RW&J??&E^l^gMO_4?e-_(N9Bj$hu5aKgvaUr=zla<{m`$F?R{%5WJYDb zDmU<5^LqMHpQ^mp#Ru!xyegi$?ed$vJUNT|vjuw&CsvA9tukJH{!PXq_spgG&psd7|Dk~Yt?uuViqj!K?Ef>cDF1DG-0$EI^&O_Sr(QH&neW#As9yAs#g9(@8)yHuemH!* zjA!EM`)#K_&k50ZoPGJwlgd!f;=|&zL-N*{P0>zz;rrmjk95oHOW$rN)wFSo*&Lr} z={C)*k8AUmv}M}rhuqd`O*)n~vw5+)JL`0fz#jE*-k=igup>!{ni`jnxS1^X7IxM@ z^hlj+!tz;{{pNbs``h!`KTP<~aA?m5^*_1`9}0d9{wHvsr~c4sIfj4N|1-1*RQzZ7 zEq45$u>23F{o6mU`_FJl{XYXI|F`}>%KLA-|Bn8x{HFev<(|*0SDXDi^Y6-;{TuCe z|Ly(yC;prNxBiWl?cegRY1O*FKF>Fmz312VO~1}>^qRiy`L|5xsd8!Ie;0ka!+cIm zFztTu;rdJ+_N~7r9j}(C&3-lS*4MiAZ+HIf-wQqqn6YV3I1~4Kksp&j z9rm9dn4R5S%k5L^e8l{tthv|T)Q_L{oZ1%KvTQ?%=A+F%bxIaIi`k>rtOz*rOjI*$ zz5JT%tyY&8HXnMp;m4dhyR}xPuMab~968O~b~Gte$2LA({d8Dr*PQIoiX1+E-e`j} zA2WleY`DQ=uD^AvMA+K)rO}cdE3G1Qw(|xHI!T;4E!uo=*Ol7+Tic(ozmfb9|BuV_ zKLe}I59SB&Z)bly@}Hrp`QL^4o0iS|?exNIzu-USf2ZefcsKP!`NR0ueIhk_A4T_k zu22sCIK6M5QjOt{y^s4lcOCEk!dcQUed|{CtT~1+E@lNp$Hl}sm;95v@NcpF#H$Z) zg?w6bShDljM_(%oubua_N>UpSJl%0?!okN{Pj=LF3%Z6KPAdB8wl8*$yTRIywN6`W z(!$xpg{M9I(JcKS@pER{kDk~Xvsh>C6B&;TE9;oK?K3;h74|dtA4^=FHsj6J>m`#P@)xZ=;E2DUOk_sX4Z*M_+k1V)Sg{e|6pGIhY)|3`h&Xl50=`CndINn ze#rmUeM$7|`VITvZY+PWm;K@TepB7z;A^F_^4>r6KVJ9#Fn8X>2fWEg&ab_7^ntH+ z%!hqbGuNDa#QmRvDZA=Uc$vMZ(D{dN3ZCl=*}PYqt7Va=b;9WTY^OG%x%r9npO&nA zT)1ORu2kH$JqAI2(amQJO*F6kTB=p_@Xd4GZ!^~!MW&e>T(&x#WMrckK0jz>u=wH1 zeaW4tUb!ue65Y5{Pn(-(|7~wUiE5ja4HZ>0=f&&z8Exg-VYMUXWb%uo4FM-V_iX3> zYa1@Ofnd`Vw9xDSHTWp_pQQf`%`NsB{~3Oy$^TIP&+vBr<7n^Y+phn~|8R64YeoFY z`ERcGuC6J&nqwy(dne))N9nGMe=HxxRv*zy{`=_Y;#04ic3*z_V{L6Z_tdAHL6grL zzgf?05q_;TM@(qR=R5a#!(=vxDtDhOsyWWJ(o-X3ZpNX-0Y&MTK5W^ydPY)ler8zv zH?i;;X;TVKl+Q==&UEX)vPs6(v^3qjqj0CsTLZ1r_#|1*48 zZvS9P_Q&dgEe5aWZ#6&mpP{2(@bSFtdbQ{O1pYIyoX!5we>g04rpu&Ty#5E}w6490 znAW@aBlBrKp`_@qdCKiqjMfRCoGUdW>&m9CnctGVmd0nF?|&5Id^F)>f!C6k7u)n( zKK#)RGg)}z`tdNq^;R8!uB-iL$U0{++obMT!LNJVN(Zkk__;Wmb<)GRRrfB%TROBr>o_FJ<2x9-Zio42m*{LjE@^P&EY^oLXWY}xzdKcv4|{rEq_ zE$wfMt}Wku^{c*61%KexJ^2s#S?kWvq z^I_lQ1zA!_FU`I;eGd33Gb!Ng;$u6OS_Plp5&GepH`f(Ik=iXk_S?_1HeNkFe9>L6 zNr#{QF`VWv+4;1UohK}J>e7z68zqWgevbIhkRI?bL!EubN3p~?kLF1&xxZ!Up__6{ zCWewzt++V%uPanbpPEo`W9Rj60d34C3pQ+h9w*VmzU)u^-zlm;-u`y4I}$IeS5wZ` zyy)NYdcl9XHNMjitbZtBI&+^=_J0OJJI;#T5AHQS{V^{$?c^S1@#aS#*KK^n$rEL^ z>(|pmH*fL3S-#EtX#|He``kyxtGZtc&1XyhquX?N$HlILkB#5_XJ{_g+IeZcmg(wU zQ;OzEo%!VPFvFi~)#XQAS63&g`}69kDSa$%(^g(R*-Px(9nZrv-+bir^S)W|SLRi~ z!BtZ3x5AG>K7cMnUEdWCl_j1^3g(nW9CeJO-cF5@+|caHpny7+1DTRx6knZ zp?bcdhWn%0>qq%-9zO8(KW1n0W3B1-HtC0{Z@;&{tCNfPG5xSr%(i_>J3rc#-%?xo zQQG&y@?BT9a7$N~z7;tX1CUvLdnz|@0O)b5qtEq zdroFOTpFi&X=(TBzSEnzX4n`{S=x0V!EnY>4R79{mTZewpXstwQ-ACVwcVHL&Kbp} zS@%lf&&=mPtTuh0T~W0&d(qR-Pp9T-3%c{aSt?nb{H6Y}_|f@He^`Hbf3$vFf8=lS zKf(8H{~6f-Fh2Uv(7Dg%I_uV>uQTlgKG-$aK8hENKbo8|>F$01+@+b@gAOKVifk{R ztW$RFqNmNq#h;!@ys|74T4%ItrA6?!f?h4d;PoBry=*JXn6{<&A4>hA-o7+kJZ>(>^`qC9w;X(UhF|l0z z=ws+oDT^FitF5oSOkSRHKXw0upZyPw@`L(6G{3*OyzJkV`wTVaAN>#2F<#k|{OCOM zy3UWyhpp6G|0L$G`C<3!-tEANYxfvGnlD|E_uF@;_wLL$TY1HgT5XZ6T%+$hZEf<3 zm)GV!GuAzlP;k>vYxAO)&n;_xPIIgbc|Ip2=&Z5MqQWEY?q2J!eOeQ;nEhkoQ@3^V zt{##T<2O3|c%$Vuv92|%p4|8qS*Cks$wR-0uA6buvkyLeUbZ?YBIYu$q_4)O>!Fz@ zKSh@Qy#Ako-S*$5_z&meKe+SXO0wp4ljaxxQ$6|Me}>KdZIi-pUH|yU``V*=*&Bxz zv`zA?6UnF-kk0zB(0pHDWb{Lexqp-P^QLl@F8Hjca^R8Hd4B&}AxqmI-UxeCSJiuY zC6`6ik2mufrzK^FJn^#Z$+)yqCbY)7|MrKgdLAG7GIewcON#oW&pZv9@~T>6<@3CD zu7|5vehS&^!>4V(c*dbgy|4F3FFo(+d9~U8L4Wp#;D4O4{~1{1|4yq@{CCOD@{*lM zg&KcL;J*vg(q|3egCeCeG^=nx(bn(;uDJ&Y$ZlEi85Du+YbBB!KHHS}Aua+l~P9k#&0N1^UKVM=?##Q0xJ)YvSX{f|%Phxmi{ zw>E#v_&dYSuI^O*R`)mOOMl0`nx!}UgZ@!@$+dNSne&u)Z~d6xdHG-+^GEk1_Z#oY z{#g6SzIQ(BAH~P##SAa((O>n)<3m_`eRV0{Qj=LGVsTO*d#|_E#4Km-I9q7CL1yE@ zXCj%wQ+-UUZd6S;oUEOo{mi0fx^&OstE-z2r{CzZs0>^<<!;c2q**qs}D(xjOk9~qV|bec5R zDl2IBRIjVAociSX-R6X>3P18F`<#fujVyz?HNI6-Rs<{$TJw-I*O@W*@F%YQa@1t zAuj%hTK!@9-dpW&)_ydKWqvUI==rYsf_0KV7C($X;D2lX@hZK!l}mqoKV-+g>!Z-E zip9Yn_IKOKRwy5Cx_;!=_NJ1IE$6%I`AqADUQVmJxBX$Smj<8Mv7{aGW@k3}JZJ4a z@I)qAGhM`JPMWMvZqBayn-yToT z{**uL%yZFPapU0XXy)1l*#*&O3wh^v>@i+-y#C>R!Iv)!4K9DZs~@n@XlKLL>Y2wP zgVoPuKgbFReaLa)NTOlE(zsrmy4b$MmyV~-?3IdGRZ?j3BF(Z+owskHzo1*6l1TO; z(-)UkE%&oGob+tU=Q+FD>_q0tEm<1R+jH>LTB)xFlGE4)!5Q7_?r%w3eiWyE$baznO>pfzUFk>WZ`nUK zgBBI-6N$*4)p{hVb=utJKdR$CYSczMe-vx3w(Z-y@Re1H!~^wclf(W72NIWuYqsm_ z<%ccRv5W66ep1*L8?|Qg@helUCL9S0QF_>U$oq9g)YJ_ZS4P=J{IRuJ6{3;+(d1>C z#Pq=6Q!9?GGd5WKW@*^m$Y&x27gq9YlBnA9w@pjp)|QPHQCBx?SlilvZN<)N@dNfh zG~3(uDgV1}DtCiZvGkLd@Z)*t!L&@RtwXX*K2`;lGj$M{()svddQ zi)6`j)oJ|^{?Yr<`r-4=ul1aj^;sYFTi$(LD}B^VDp@w}y8Hf1YfH6n>&=lqlxB2x z!_PXiK5fH?f8@B0&lgSQ`tn(3y~df3{ko@(SAALT8C2<(JoDJL$fjdXn|~d%=j=P| z)c;#dso-;AXm*0?G;i6qY4YrI9~DaQEH?agjBlN=?5u$7T`V}_x90B@d!JW)jhtNEh71gzDi0VeRVFtu$V~Eo+BNf>$U>{B>QW^y zj|Hy`Dhg;(WId~SE@(@##8FGHpfbJCnb=ZMaiEOuPQz-ttF3_k?FZ@C^?A;rVdB zM2-K4>qqr_<@xs5KdxQ|nhQB{pYey;e};pz+B>$~O*(zJYTa($ty8Zp2%5EAr}5dT zNHzJcbl)eYAFsR$ou|$j&DnXz;O9JJ_QpPK*=Y|9BkP3rCAU`WF)5rehetW6jc=LK zRvF#6IhR>GPcNU7s2McR-t^(E(53TJO@a?4ZMu`nlTu)6lo@*F-{O|la}Em!wOZ}S zNU~es{_C3DGG$3`zSrSPe|wrAt8dr-5R`vQ>huxA*YO;eAC}CQTx%1$C^|MPFl#^G z^h52(F8pZr+}x&IT`&8-t?8AS*+s{1tEW!Vm?UW2vZi9Qzz%ipBQw@1E{*2c;n$WQ zZ@p0B*xDNNZ!(6$XENOkC%1ZSsaqSR=~gpoO3AG5Aj5|z>erSQSw)&WjQ^XodfKH^ zuR`*At=5~)l}NbjSFtiEsPyIMl}G*N-kK7!=;F`${~1^&{by*pPY7;0bK2yTrRJ4ylNR@%D!A!qEG%Ae zDCqEc{<#VFbWP~dOj>bmZO6he zk+(s)Nd{9jE>F{%UDTqPToBwEd1|dkz~83zI`|KTnz#Rle*RnL-!e6Re`nii)*sZb ziP!J7GyivE|Cav@4Qcre@te)x{Csfwd{?|wPMuOlaMX|W58IE#3uVqKJ=@m#;qgH! z_O35;wU5XtUf)yuD4+B8D?7%^dlJi+ty{a~<*mojf4-%+9euv%MxFfOurtMVa>o;l zt)_nXGx5Na%dI)KT(7Ops8>mriAzp@mal(C^BgHb_ctDNw?6gZ z%B$oLTVJ{r{Mr1Up*d{-gH`i|zE+(=c8pGKl}7Y#*($(!fh-2PiU`EV`iL}bk!^5Z(nN5u_OaazhapbgNQew zIeC$tYg>;#tAEXB6+b`x(A9@Lzvemjv_?hbyqBJF7kh+=dx3OcfD@ktBR_uimp{g z-%OTW*ZlJ?Oa4RT{U4g`e?*xB_I$L z#Wwyl6DwZMW%~I}spToXR=pa#Xt$787xrJ%IAHRAf=khxwZ+DV&qLTXQKxu!j7 znOxlM590rL_y0(LEZ?y!{jK_c2G-2Ki|aK1GaL-G&$LJ}zxJ#CsBUn`hwpD5Kgdkm z-5+43-@H%oM*ODu46*H63bpJ(`!4U3&ieL3rM@*PFm1cv98sO+YTx$Xj1Y|$jXfED zwz&J5#jTH}hLc)qrx~p?lRG!pCf6$@8ANuoFh#!m-yPUfvpXZ1D!CPX}AI|6gQSQFUQFPwag%$O#TQ^=R z={37#puBD4<+r+T6C8vzraFiu6c9;R<{zL9%6I6n)J8%C{xouNwN1xoB55kAyN@{oYsdsE%vzW2{xSP$Fw>JCw z*rk1s83nKRH(2Q#vQ*;yt-o<%vkw>O3#Uza{YdlLyz0Z1wpk%5FE1TU-MYcXbM_;H z8#|A!D$O`;aPm`6sE)~puP^raaZS_8o0_90KmWJykI;wR`YeC+f8;;7Yi6qfbV3-ssW4!&^M=`yKe+uUdFYmWA zw>MozXcT)IG-TreGXV(4-u!IQ$>MmuGaGNPpPQ3jBd4}b_Ot7f$J&>_Pxf5C*gK>q&AESC_QWSQm;AKc ztg~A0`01NlUVctCC@JK>xpi^tE4#2Qg`1-nuU>ER73a1=4F=eP8GfXbWd2FpKltW< zOX%702h-n#{#JOQTUfg4Pwm9cTXpQjf|}NbTRhrxYF_9hf38=b zf|dpbo+>^g>vegp|1^oOY*#I>PJF*6lxK1C<~fH2yDBuEMZB@&TAFEb`OtZ_lNtUN z=aqZbt1Wh$CNCY{W;ih@Z1zH}zJL&w<-aceHm^UpcR$BJsk*cB?El2?*4^CyA$UDw zww3sydY%{eR4@J$uDcsAW+(SU*!g4cw^r8cy{aGl8%)~&GqiXguCm#uxA)psYhEE; zsai9$9k(mCN@oKu8mEdeCw1KPk#Do3r~NrVaAzIt;%DmjfWoI z7AG@b@v5xU&arQjz{U60PvJ@U& z_oGj~W54Jh*N6NP60#v`mskV9~)NKJnyim)_IikojqER$4-8xJ9pQ^ory2J=G*b}N=0P# zg+7d0@}FVZe+JQt`OY8wTmN`IwikXS@X}7|!?fl#6|;|6tv#r8-}k~7S-Z!fSGRJW zI4N-RM%0}c4~KIn`i$f4XFr=^Gg<4*=QW3xZ#s}F!IPHWyZYU~_neKOP0(sPmvY=Q zS?Reh^Ju)=)tmPl4m>KhDdW~Xc=%S*XP!8D*4E|K)jn=oTQmY&?{&{w@>qKB`r=3D zf2gzn5fOeE{zv5Yx1@{z8M4kd{p0;H`9VKJ_C3Ro>zlXiRev;Z=EJ|*N3I+HP!G4V z{kCe_Kgo~sU0bGK*4GnlT{H33dm~@ot6R?)oXtD<_l+OZHet@mk6wFC|D%(->CDQD z%k8RWL>x9cvuV|g8s9|=R_nM$MlGqGv&t!=YKvC!O23eol_rHZYW(bN4m`Z`>bUaR zuuz-$&2z0Jp6hJZJ)8OHL*c50@vp8L{9G!bzb5eT_1>(~msb|cg*^SN4)#~wU%GhHsD z>Q(V;2iMiCYlrXOym}<4vQ{H;^-0SMOQXg8c-@5qy_ZR>Jj~vCP^%=?#Ob2$uwzrqP#gVQy8fVI9ar6v`x5^d9+v*# z{?_|9_woN{XbJz;_;dFi6e z@aaM4MJMdqHB&e0P1K#}uMa;?HTY3eCMEL1&*GO!M(EtAx=Twn0*?kBU70v%zAo3L zmF=yT*L!NWUwsWpD4<>qq?C3YG*KIFx7{Zc=UyezmD)*LvQH*u#-#O8d0dCC*IF zym}_80qXijY8-)f6<7Q6biwrrG`Rd=8Ljk0Oy!k#IA{1lH~ zIKRi|?B*Cdd7({z)@!YIS32@|_3xM%qk9TxV=|tau3Vq%&-W>3b;~9#lZWo2VN)_5 zEo@&Z5pXzgZvEx+Kde@Nn`XcH{2#&lkK^0Fyp8?RFIso0&frJ&Z<~tJhd-C?+VoLv zqk7Mu`sD5GVz=fWmS?KC?6GU=hK^a2j_>f+QQU9$$m4Ih^r4^j8;^u9?moZb*^K`T ztHXco*|0-TdU3ebp~u;NrWseKiP?CzJv<{?C9-$@wJ^)Xk0Pl}t2?LEoo0gL;}+O+o7TG?0!^@(w9mArPw;AdX;jAu8zO6J_POr3o6>f&(j)+0{w z+5Z_1^89B=d-`{({e#K%8@?av{BpZjJ#Nq}e*%J~m(K`R*S(A7x8_ zO_0qind^P5=*7P1KNlRA9nL*;XkmT$#FDsS@+zs-bnsK<^1E`{-S?e|1&g||2zEh zKLe-R#-*?3seF__e!p{`*pJ%9`knt2V_$CnwQl~0-3KODI3M;cP3GJ9$g*Vd$7#CU zKD+mAXb!wGi91t2=V7M$`tzIkS3LUTxwP}li=>Y?-8rAku(~-fy0y2e@T@`PwS1n# z_J`ahy(WE=xWndsXp3RYYw`9rZsr+Rk3LG53^{07`z})^jQj8#-y9W#kYYK7^Vx}? za!wo0nJ3KN|M1W18y6OK91bpd^{8NHU*gf9MJrZ3(hMs){cpXS@#^?_?JvLo5te=& z{^s?62G*p%OZF)K_OA*2@$rM+EBTwJJ$7yR+gSf#+AsUQExF;x?r-*MeOR&9#(YKH zmG~{`4PQOBymdcXzg1*fCtvHsr62Z9UGvBI?;IQT70!td?+gE!e|(?P-j8n6f3a$w z>x=Gxl%;2RU!+h~tD;Zg(HU0vu2U7+T92%Xj~#EVDBG&J)hY5ycKxy7`HwRbHtT#B zZe2Ms;l)EE8$Na388zI8pZ<7b7JhirfyYJv&-UE*|^0z6NxZkaOMP_$~c!cYdh<$Hn=v z{^7ozkLqu!KWJUvyzqnXhmYGkw)|&clm5@p9`$YMqk4wyUH6;c&2@CXAJo3ok z!^-nq5nVG~r7AqG6imOml;g2MHh+JQVfw|iE05%#vC^OFbX@UyeEhDm(2v@83Rr{GQ@}hNe6J z84i~IVgJv-(z)TI+|vBttaV2=&hPopu=RcW7hk96-tj$gCLg3Sw#O-6G|m2NmAZTP z#V!3p6{kVRlI4_qo$S5q!@t#QYCJ#2&b{($>iV{ICU<^Fb2gqU*13O#=Q5|a(P;~1 z;hsYumh$-VS-jc!QN&R6NA+xRsVl1zlKYP(zkL3As*L-!)V_y$a%VohkumtP`ONRx z>${hCocz?YxUJ~dj2^Y@qZ1E>oHv|OyVPn%&T84Ve|HWgE)KK`%{(;Evt{wj2Omwe z!VaD8FrG6l;*W0nq{N^0CI1;7?2zBgf9QVK{SR*QZ@WKKuCR8yWTX9I^0%yy>PObM z-jn}uciYT|bM+5KJ%981;k6%)AHH2a9Cqzu)XQCB6PKGezpb&k726ZGZBj+jyZ;Oh ztw~$3dt0edRoo@h zf-5gBAA0s9XS<|i*jjIn<*nVvEfeLGgnumm$E$c{YxjSKAIj{9X4m??`}FL*`;YS< z-}`>}6Ykn$7G?e8-Q$pHm;LWBh^5C|`MP==SETFPt1nLEEc(}fMAu*M!KrnArK>*d zb&XrHTx+VzhdZH1e(0E_YkK)=N$}_i^Sa5s$$YpXU^&MMH}!*0{OWJjq%766aPKTQ zH6=Aw!YM}i(B&zaFZSLHn;SK0@9ouAeXm~1U)HVJ`2{@j!1z=Bcin%6gYkCK{}~S2 z{?qv3|1i8~fAaeu8uD+sSNzz1VA?&~?H|+MEc|Wta=z#u#w9oJX5V_&uuuNlp1?JK zTtCLWKRkbQ zK9B0WjVm)Y-K;o$aP5lMf-l7x9dtN0JovAnD+f!(=kms`Ap=Tu1fy?udOCaO?7N514|3O>do~MUasjTlqdN8)dQ>Z zPul9&Q* z54-#MD)OFPdUZeW(jU){^+$JIUEWgi*YB)a;ls7k$D?ZW(^tHb%Kf^(Y18*(b0Qla zcE}@&@ONBiu|@`$g>8&)jwJ z;(=pRlslJpoY}vnz%(;?(;1udckcgCUH?b;_QUu;!q(qRegytD`D1x;%Zfj)%U(pK zchs5uxOeVs!j*j*f6}jRSuOv=Z%^*(JG;FrZH%)F=Bgk1CLSK1e0U%Kr7!Y)x6XXK z6=nVRxxnKMGuG7lm<6p4K4J7~M~|Mn(_a7V$b{NGPi4aNmaCeE8=jH>ot7A7vNEXj z)h-DiJATIYgAX?RXONuqaP?uXjXQqjNp4H!ikNfMD{IMyOOvL&cv`Z`)lEL+)Z(xR zFRm$?PFo(w%SQyefC-U!hc-$U0wQ7Y~_c? z4_ePREV`un!ENg!{nl;wIg+!ai4q7ktXmQK8pn2(Gds3eJi+7j)`}Lopsipp)*FU!Z3-o@t#XaYXPL;}PiKa?~&Goi(;2oi9~M6@KVE<1^S90)>c1_2oIX6C z-_EEe=11}){n>YO&{Yd*YEUk;hSc>xBBMr-wYcBgWV3 zE+xA0#y{!hGanR$6b85Pty35DlGu5iS8JW!wBVUG^Tlm0^~&e>A4o8c3G?;~TFzzv zT2^Phq@L6~y`@nWGcFytbpBdwxO`}$;pU~ytyNP#SlpV}C$#^QBWT&nt8e>wen|dj zU^(%hp-Jf9Nh!VQsjF);KlUHGEARE;>fY~@ewjDcFqSX*BmF~lQFd9t?buke$&d5p zvvHJ#*3CAK@!veYSs!xqFtqdg*@#LGGhA``R>5Gq#-8{?Cy2XjOti=<7tI zjI=MCeKwhXxS^x6;fw0Df_~12pI`mxS-UHuMlL#9XWcZeHmTl-hmEarOds|e9ly4; z``Dgi`U;01sXI;eOuKw?Rq7n~BcaOO>w6cg9+^3>yyIbMThQ{(KD)?mnKFLL{2lXT zAK7otZ@AC?g}-4xlO10T>xXxz=kwG^{|J1*-*QW{LP%xj#Tv$ky4r`#^i{W|xQL5Y zh2*QK?CO2WnRvE3#(!4*nxF6L=RA6G^gly>+RS;0@%-V_)>szn_-1`Rd?m=wRAF)C zrAd>XP6?e8l&9W!_y^ZdJ^v}GUk!tgJo@xUOsG#;wsO^uHMv>=zs^~nJbC5Yjyd65 zj+_dbJm1z`U0vPGrDb#R|!H=eXjueS@3DdwsA{NGiZ3{b(xxe1= zOGNXT=&DDHd)mxJUlqz)Uj3-uQ8@X?u|3nd3fRB3T0F{nl-m9%=C#Un(L!FI_^s<> zFPtfss=VhvGiil>@@bwh$yEV|{(7~^f0_Ph{U4F*56lns|Ipa}=I(z6mXlX(>_3Vh ziQmHhR`tX4qxVI=%nd#q<p|OgWSm@a^}L~tzcVMhRE_48hsH6d#Y0y-T&fdh%--_v{GvzC z10QFsIjwypq&F&Lg;nJ|E|b+)*II4)@O7rf)5yHwnMqj}vMtYMrAFAuT3uN>!!qdC zs)}7RJpDwKo91j34V8L5Gb}Q%;K7_tuO>`?aWusP*P2`T8UGnRMEKwSb@?CX;{OaR z|9-su9Te@HxT414;+NI_EPuo=e6?sj+qU&%_wnGl{0Ef-Hh+E_^`F7*!`CCzlmzE_cc*y`xkH784T)b{ZFXONHP^=5217}h6mbiSCYGK_7@-q{uP-)j64XFPg& zY>C$8xiw;ejb{uatV%PkE{vA<=5`k5PYheK_}vo;89Qy^&ZCcCo?90_Ibl`W&Z!nw z8%keXTIcV}m zAB~TE&3&5A-FqH=ZOdJ;C$X7!Y#*jr#lNuZi*I?zvt0jy&SGwx?cCFT+nnz(_`EQf zxBF;eSTg71Vve*^`+t|#$MuJ;v-k7g{dY;q|M2|oIP-sJcXck_`%!M=!}UG$+4dCc zh#92$TAe;3C-|d2y>R_;oy7e2Uv;a)Gr8~kz5M)7;`pnd-(^z$w#?&9{Bc>-owLGe zie{P&dvwQBza=Y<%|4>}G5FZCD=#0b$8EIa`~BdbEI;Oif!<(;b!$7s%8l_wu@ z_D8VR%AVf5svE0*noB*I5jA0|)YL4$RxL?3eT~yoUIr{|UERK1)i1Pg%EzzDf8U0{ zHaE+kp8iMl`#;_T8~*P7&ycaxK41Ul?QgC1ZSq^+O`FHDck_q*K z{cTn@W^#NN-|rEAG@tKB|387Vdfy%$_L+Xv?E5~MA8Q}TMk-x-y7Py7<%%E8(O2>- zKSe&ah&Nt6J5}UE#L8>O9vOb!u(MafbB~)|tBz{bl)|hjs}7ZXxG?!Z*cM}-?P4Ep z%vo-EYWeikO^3cE$MIVqd{}hn{_RVL6F;nGSoPrDoekOIUB`BnZn$@!_ie1#kCkq_ z`qZY$3$_I>?mG0ScArvd<$AXIgT?jP{y)^qmM;KZXxjAX-@$o`KNufcXRprZstEsf z=kMe#-0wU7Gi>Vb&`sE}f8)ipt9wir-p#)LkNxwPxmM>M@$x%eH=QpNYkH&nhv9?S z9M?|q%}lp6OYH9D`f6yYmfcm}CvG;?>&nI(^OL)eCQaiOS!gw5=COHVp|x#%%gTd# zEq})x7H?|_d4AMpvB7DBKR3)<&ll~nl?p$STG-2V!{cPa%N0o*wysP_bTd5iXlZ-t zM~Rx{yg_RvgHMO0%*j6g%lhx!{|s6DH}8Mj`lB-WWAwL-ALl>3e_Vd}^=BF9BlG$G z_%Hj>cHe*RB#}8UrT#8mvOMU+x&8UVEBAf)-mzxO-eUjcr}s0zePWt=x%1$of;sc< zP43b9?e4TimFq^1(^7Mic->PGu@agTJetY}Pm;bIm_i5ktXERQ;pZ@&s{DwTi$|ZZlnXN01 zANE}GbLpWxqnnqXJesv?k*~>;)y0>Ko(DZCQGRpB^3}?}!7Wc89;*y8UCvdqW3@_a zj#aO@zo?Cy>yb}~!&X{4g|0l$EMul6lI*lpt2BAW^@U{AakgzWqPL6Xr$r zHCzr%&`zv>o#u$2GPS=9eq^yzeJ*m z%kKF$e{=eq@7blPdb3M&KiEIC-Ft4XNx8t;L>oJ%3(B)jMdWqv>WYpOT`H`CZhD)bLS;Hu8dpT--dq-w^=!R2pLNZS(oXSs&WCS{|LH!KywICt=ihO@n8!}7H$Od^(N5%$bL%J0q%3u} zB`*U$$~vvJQB@Dqvz#0%+!_t*SVVxKi(kG@hNz!pYicy`*J%D z9G_=&Bq{abpQ1ncTY9I+Mg4qvZkkxp>VF+yCrIAP>tB+w@vigYmsMqxMZYbsUw!ZB zvKzM}+$&dSZP%|}l{MWnTg1C?#jEg1r_1ZBHL7Qyo+($|nKJd}i?}zMm-~17O^MMA zj&hnJ^E~j-oY2J_yQZoK9@EsTJQuao^Tej2x!%=ZWn?}7uIihsRie4`^rOkGTqY|H zo_c4pGI-fq4oCU3>VIUqe>?rVTfaH}jqLBZisgrHJ%7`k`CIFc&yV^=b?2|mO547? zCawM3!kxQ+JWT)3!1evu@x!-{&0gEzCUh@4Iy>s##w7=f7vKIn`LLAV(&Ezc;+5SM z;ZJ@v?Kl5s7uY*j!r$)E9W`;5mm!{44y0C=`f09gTid>#^SE%lz>jj{L&=Jqho)@W zleCs)^@HWk(qDE;&E@*hb6;Tk+J7+>f@c&;00hi(e+|p2kPf^M`k?GdbNa{$sP>$5St* zOyaYyExIgy`2NjZv0J`P`nUebrEit%GN-2nFN~I*7msVy^G%cZsFh4be%O(7d4!?=x4UsJq%zOd+g_LZ}$|89Jc zTqZ5rxzICsDaWeN7sXG0#F%PLDm?hKB5H@%zWX8z+b$%V6e}T zza{+edvlHDZ|S-_*XuX*_inM5n45nz&UWkH`F|LHJJlabf0(=|D@^&2P(}6eTgN&x z7gknnJ=?Zr*R}a&-}S$-ZJc)V(T>kaPv*+_Y`l@iGJ&iLI51-!iL2BXD_F zpEA#i^>@!EEsy67y*ByVlsMktZ0opZ`%K0*ZwaX!`A+1=sNRvPW{gZ*CWr! ze|WS0hu-?XI-#rUA8oczm;YB`!hlWf1@`OnH=4gm{m;N^@q_>4EPt7Q*Y1A^*LD7O z^+(V>f$JurKlBTKOVr5z5EcKU@~idSbiMvZk00-6{joagddQ1_s4RhXy|Rm%ww(Nv<2IaZ9TNmbb2Y>u>iZ`0eGUb5|<(vOu7?plAV`fw&bHrsm2R?cBNHN9~G=(^0P7Mmd+BC^JT0e`>L+?wTcApwyKWSI+I2t+iM@ z%I=b>M#{VGB9A}(J3WtY`Sqed&7uwW0+xOBTI*Gsd8p+1mp{7y&Uc;JT>f>(apjZ7 zIyKq}sc$|;_|&P*F^cJz_FBJnv6g-CBc9t@N6u}vTyl?Aia1H}gmN z!+gg739lXWB0@oD=x;wXve*@VsAC! z=R3V~@kDXAKFiz(Q{`0tHut`)^%p+8Ge$M^VbMSChh95EL$^Ktx8bQoo&NC^vFdN; z?@mhPi zj`MH7v+)mqa5KxiKB}Xa8_eu2JFQ?|WL);^tEzt|&kQ)dD*Vwp%hT$uF<(Bj^XzUl zsu5Zp)bir6v`tx{x2WHq;;M@JwU6!`idwg$H&Qs&rSKaw&meG*?)&lep>YC=SnAy5%{ICg!P8Wo`6ndLQFkHn{|pZw?Eg?ve)PQD&&QEJivKgPy!(;eQnRP@IM2GoO0oumq}XgMrRCfhDCPH4R2fC zaK`Y*EgQ||Ut2lO^T$g!pWC6_vZG(zZ*7*v8kKu?6;s0uS5Et!`$)%jUgE>=T-7qF zQdbHh-7;r6mD;W|mThR23732L*-B)}N*j|+e;(UD^jR#b=`P7}sYg-WYn#>dtI_`% z*fnc3KkPp&|3h2-k6`qp`)?jTd~eo$1E5bFv;$ zugn6cL>r#{(amc$W#!X9rU$QV?#X%d>|@dS&-YYL8_g3sov?S#3TOVl(*-fbGaoGt zTT;lIBC@b`xrM)QFyCes(6wtlURyTaye{_8NM_gcjYWs{u<@&%-F!~%_@k_QvzGsz z@6JEzfx*X~=TXb7?GA2jUD>w0dwu&Kr~eF1z5f{w7TRauzZvZI8zLw|tQ~B_`NM;?|kNAZ(mRH{D z{o#Hnyyl1WBg<=F^Vw>gKDw<`iq5=c-cqWUv)S;##rZ7BJKFkEKJ{6j-_g(6x^(h| z!y#vk&WW6OnJ!^tE}_I466;c%S0YM;kUANi8^2(Jpy-s=*(7x4AN@JU&?oMSdD5KT1wBE1t3< z?Z(N}jfZ?66#D$qe{}xs;r|S*`5*b;#D6^hkIVkU>WACkEc~tchwVq{hv=j8<@O1I z_5*L-e)xPBXkkUBf9HMP8sP<5b^4Q!#Ebp${qX+r@%@1vsXJ1K20vNF1r70!OT*r zqBGeKHwv#j!X?ojEk0dmox#EIsWw|z{p^)-lZy-U`*6p#bE&)Ll*Ntfr~mfR%k7ya z*K1Rk=+7K3+PTtc&g#pD9{wmZef%{?uDbj9A&EP>n$IUMY&rEh@#p@~`Ui96x3TVj z`}wy}-MRT&-^lS#J|J9^_d%pi>1vI{^~-m?fB(GJ1w0Br=?WxmCJN1Ufy>8Qw&>W+v1?Y z9_65Qa&3uztx>C{N?cv(7pm;mleTic{e-mBmIp$P+~Qg$ZF25Y)w}s0o_C(u+*9V; zvDUZv%C~|ep$AUw$*|hGy!G4s(A8l}vyA8LpLzd>f_jtt;r&1K;{V97KV08=GB^3- zs{HQna_S%UE?b_u_~ovD%Rg*B9xq*|{^Qm2BT}w&!q?W=*sp$Rr}D#kP0ZfbE#LV0 zHa_g`4SRI$({taZ$44JTZC?4%*CU|fD388Ss%2Wa*E+eqGPX9iRTdwU3|h4+bk?`4 zhLWv(N>Ad$m$$XaO_jPCr*ClZvCNC=Ii+v1DrQbj(t4Ef==IeHYkWSv`na^c<;Bw* zYxvuDbX8_ewLTSex?sZT4Wh5^-%ehYklKCRNn**Px*7i&4xYZhHFo=(pZ^(Hw*A=s zVew(tt?T>dZ<~8=;&06w;UAUDUS6;I-ub7n`lEjEhRbz|w_n7`T~6L{Re#x*ABFlI zIXQW{YoB=hiCkCV?j`+|H{W;Ljt|B$wm$F8AJz#TIO}bEZu6Pl@>~Y%TNg)3=rkK0 zNaGjyx6`UbOl)82-_}V-!)6V|^ImS{uzh z^O?jNKY6Wx*XI;U%=jD6*?&emO(t~4v28|E40c4_IQ_`rO2*1dKlykL23Gjwez<(-*3;{qOMlFLDD7e6zAoxz zo!Et(J>2FUbsEvPD}+xUKF>YJx$D!P)<;=sHikzhoLcex=2G^Shj-4mCQeTQ!ABc^T}oDowet#GyJ3Qar?pk z&ReYao7U*63)DFNxc#y3{_+0|d{3|ZDPHpOdBA+<4}GhPbN?=09qYY7mM8O`;+qp0 ziJ$i=oVQ48F%(+c`0$Ot;M1E+y{=@e+TpWZ=aJ84X=j5|51sa8Twm|qepg3j<+F{; zC9kdwvX2ST4qE!;dBv=s=6p}@xOef%_&*n$uZwbwO$}AN%i42=dUrx3=gkUT;F)+)6=%n zd%}9F=M_xZG2Qft=dx?!Mi1xYd%YW?t9bkUwKZDdCw;#PLGYg|%)pOXV>Ka`?^gTSD`>X%0?C4F`O#b?N z&3;tgqkh38pYMs#&lAAa~_CwpzyA;Cxg8F)^vI9d zh2b4Bj#IB4IQpS4&|7huwBek>(#$o-^$%QL8O*fe(qgU3JK`NP>(sb{mpk>^Oy-_* zEO@QN(=B`MsePMKC-%^$*Xcf2;P|Y`^_5Y@ z*OtYWmdRIbZkwD|*7BBgmhSj>Yk&HU{|p%?_DN=T{tk`(BeL(u>A$NVsa?ynPrqw@ zJSzUM@*=bCRriGZeYX7QU6n1TCAG#*#;PPvY1XSBw_;vrR~Ih3ed~tp-Yu~f{i~w+ zzlL@M{n}%<{cC5?q>6o2bKdj6c`Pntzxi9t#MNg*{cpwj*>qVRzx6xD-Dug0-(L11 zfkji}Q#MqD#y(QHlJLsgAmZl5kVlJoWHxMh_B_fo%m2r(k9E!Z$K`+63Li3)7YRRc z@jpYl{mskX*Z1+iywx*p^X(r^y87R$uKe*_wr#%j-&r3288+3Fe+)nNPiuRh{zK#7znMEGW1)ket4^4{YSovw58U81={zKThvb+1B+Y)2eK7@#2cS%W)rV zk1o#KCHtlGaNo4VxC)v1D!o#BoR3JnvGbpJ@krR=#19{jJlGpIQKcyD{p*8bKy%^!C^PJiTcUvz(FZhTPx!?o|*{{&Wk zo11*J&g9Y`#`4rc7P0!254*F%u3M$fJvwFIx5BSJcFO7}f7D)Hc{s*+dV)o={>m`X z7vV>r{8S4JXKp*Id1=l^p@seDin~fSzd6;Xv@~VujI@%e>2V>2f*&`n+H~y7dE-03 zxjs~G7kL(WT)&YDKUg|{+wni*>;G}7{*JC-kNMkLYTsSIF}!u{{^Yylz$Tc;nLr*^rd{pyyt&hFQBD=NbI zZS+|`#tWxjSliw&|J^RSR#8m9tmvbj{Cr>~FAq#?|F5XO>%D|7Lkb zUh3J+GNpi}etp7%6O%sue3%`!Fj!Fjo!|8%zuFu3iA4W6{kU)YgR{b+AL&vz3#hq$-m`H-4z+T z*yi|C$&})pQ>NJujdYlfJx-1`D43_tKlS0?wW+}pAGTbzn)>qLg1PytFFl>>aWZh( zdI|B#4>tQ8s?3Xh^D^o4oKhb(E|UV0S5DK^4UU|f%Mo-aczxJXk7L`EvP2TYwk+AX zXnEk)Gd0n_S^qN}4ExWJX#YdA^2cQUH^m=U)OcU96S|Y}`f;v!@Q3)m8pd@mf0cLm ze#(gYyRP@~d%hpVfmgop`sL~eZ1Z(HbgOjJ?rp!-R?E#VE>4#{o_}Sd{mn0*?L7AA zY}98DJhoQy>fxlllh$)t>@t|M>fztLdX*2g{p`b!{f(FAQO&w)AaNt{N1Q#^X3eKI zpCe8@6tkK&mFvU8&O^V;+gAp2cdqmkDHJ+<^_#c2)0}zg>@s0&%e1CSRlJc|{jck~ z;tlL`7Ap5YRQ5OiNq^M;L$&r_1-)L_fSMD0RpFR;g^&pkQo8^C- zkD0u9w6JaE-T~YVf^<_Uj%M{W$SpR2eb^mbxpMdpR&Mn_Ayt9$AkzM?s;gF$O-!0#x z_om#6*`fBX62i}xe`o5BA$w?F8xPv>vh zFIe(JZ{dgUy>&)WKhh&VOk2D(vugP?lm85&(Jy{I@7rhbW8+p{y;m8!CCML72bE^? z3%?W>uVZJZ=8Dlg8k6_x(wZOljaRljoKYOG`t{A|Ur_bP;qW$?eZ}-EP)w)G} zR=u8AWAdX!QoWW%TSe3_dAzD{<=hYRIW8>@nwlqlAn5qVSdVLq?6l4 z>{X)JdD^fd=e^0HhnW`^y$(JS{$S3dHJ>>yum3yWeuMpk;$BJ&- z0*}Z<&-$>>cY46L8!?v!+aFd*Zn5aMTiL&!YX*D!ywa(Ui*y$AwjF*XqxEFwGjrLf z(!|zNTE8rMm@9hx0-cs@xY@?s{9#V?%(RMKrmLRbuzX%|^5Ktil{TRk#jc}Ch7ndJ z#x{9Iq7PeoivP4TOYMkG``H%%+D_u{4$#TbTi?Ig`#Apg`fsT}vVZITJ08C|xBuYW z;77*~+-Ix1b&u~y|3~}B`N!9qJA9aXy{nX8{KuX@`aceTSbZ>l^ZP^R1*ARK*2!mG zj;#s($lg_Bv*C}!zKtKgw{NW#lV0!Nv*M8jKl9wQ%5zGsSv&p2C1)mCR7pfWEZi9u z-W2-LX6L!|Xn7l>M?PuMToJ48Sh{n%wK?`o|7Mpy@A~n-WtQ>mT&H9rXQo!#iF5WI z3_Y3_V&wI6Yi97;mZNDqIukxj4fAg3)kw}xt*pxpmYu%mysVCC&LxS6IS{{ogcXCn{kgAKW8{+xc=Ix zb!DF zo?-J}idM3(5n%{mGw;}A`S88?i>U3beq+}^~(rLXtNeiWOYyf!21+RRGH zuJ?XdxAb~(&$SQSu&Z;HcDMKG%C*mXyS$|}l{T(#U)Z%cn7?bGyKwtjajq@ems_(; z6TY{4g^Db+*sXocbN!A>y;(P^Hmr48>m|B!Ush?xxsq3xr|tWq<#?>HtZYwI_55@7 zZ-qgpkJs>Q{n1et)flLtKijr3un~^PZKXE2}7#K78L#+KjuABcESY!V) zG)392Z~4#gV9WlErPq)1H%58i%H03qWB!ezWA~5B3I0}cUK}MaSQGstTXuPSPK`yL zDfjJ{rM6MOy?%&YGF^P*hxWtrE<@R?$F6Q(Gih&C$i^L+ANHvWh6XKrb#80Tw6#?~ zPD#Y5%GfC_`53BkYRg70lMU|;&KSppEdJfIve--D+P2UcflGD#!aJ58vG5358@Enw z);GyxLR00}h0fo0_)4!vNXdsERmO8YRz96k@ksIOI>o7_R_$*Nx+i&2#E+MlZBJkRI?CsJmEYn_ zn_Fq?6O&ioIH??U|K{yjR~^p#vr}iBnQn4sQ_itD8P6pB?8T=&Ug@+}>%-FS1CO*4 zH<~<*>sju$B{6EsW2r66txAQ0T9%57RnE*yZaMqu4PSP{s?`sQWz^(lo7c;?ZIc%D zGF=hc?Yms^@|;w0agCEEk2PIa$}X*Zp82QkKf}Q%@teZ7eq8^L^XZ54-+Dgux2s+I z`u?W=W1gz*UGLVsP208alASU6I#MXx^jP1;}j<$msUTRkIr%&cPtq&FtR*iTgX3X#D zTyD{Fi!q&&cr{8iJGCPJjZXGq|62iV=@UX$PI@+FrSI=c ztuluhJC}-^a&F~5CpdXZ@}Iu?gID5Yuh{45-~P|=k5m0W1Ix)D@x_&EYaBkdch)37 z=9kOZrO@^3`Js7yKW0AiXRXM)er(p-1x@jrqkhC6+|OsHQ?WZ>)}zp_^M`Ml-dk9l z^X-CO2*B9A;LoQtBP>kb|o4#3_3m3or7@6if z;c|s})s0&>*ZDUu%=&RlVD&c}-&skU^mz=wY$#m(clD9Tr;<-zEy;S6wpnL8d*_Ky zoJmH1%=Ppt-?b@Q1CU>8;d7;d57L4(ouHn7D1(lK^6-;m0g*+RxupYu5qo}vBtF~w9@k0k!!2twmf^h2#6D{18a!|wXBll;5QK5<8VZms>pb2CeS$JE`4-?VrA;j{intfn0Q zrt^2fvLDQqAKCv2aqHTh{%!xrZE5PmdV#DsrAu2}H&lL+mX6-5s~C#g%VsHUW}X<;=EK)P+qZOzj&AQ;`ev@z=ED!Q zg4Q}MlQW+F_lS?P;c$}<11fjuf6ZT@~qvu?blbX+mh-Px>vBOfvXU^{VBume*D;Q<2J-P6bbos`jn) z+h(bgniZ-THZ>+FqHD^lOG{n^t@K-(SLw9W%4n*DpRSk4?B(JT=8|=n{~fL0#8r3n zKLgJm=MQJ?Gwfz$et*089|7PRN zIjbLkta#piHtVy+qr#GZ+cuPBInCt=KJc($OQ@<=@yak+i@*7zT|KKDlWON~Shdvi zVZp^EuZoWIa&1}}Bpzy+ZZ$RQ%1Wt{DbMv>mETA`FtMK`|HE><|CRp?nf?9uKe*Zd zP`hF#9P=am+rqz_RX+Y_IAVG9QIyL*kso0-st;|Gcq9exnAGw9*!uWvbfT8aE#Fzu zI^T`mHfA3TS(Q{1b>d^+KB;;9O+Ttl9?kI+7j2oQnfy^iHs(JAr{C=7Auso@DzM9) zdd_&ce#Ylp!Bf3LG{V~yKgyZ^Ha}dayu9sbnuX5&&d)sC+dkb1V_K3K+-l=8k1ybu zUue>j#YZHsbER2i6))~wuqw6GFjQ3QhL1|2`~~}_{W0<+AtN)eA+tXRhNDHICVBdpDtc{)C{###9Wnk@V zf<}=)D*tC-Z>YE)|KsMP`X6fQe}uyilurchOqSoG^yAPkM&;cRufk`|YyV*VF!$)w zIXWt{j{Ro{{ju=z$xWv>*SFtUsMmAy@Zks^d%+)TC#71fn);t%vr*5o)|^lCm?o{A z5qP?y-z@0pvm2Eb*Os>aJ9@Ih-S$Y>`gq>3DH%!2x4DPTO}(;o{^46Uc3Yi2vg^!uajV&;x64CI3oYW`{K?Z7 z?>ZQ~az<^a)@t_NgAWUDth%uxq2Oj4mqd-Ljv8O+9D@zbtseir3kR)@IV|3L?2%24 zscGvu(-^eEiMHkHw)sK0e^Twfo`ut}XLL>Mqpj z|JeM+H1YlS58k6ei)<1%-C|+U1Ra#O$%o{+`nmI!%DxBzmt~E zN&9zc^Ym+lrNutAHHX%j?X3*$o4DL*Tkwoj$-ScU4jUdz+-x=D&86ab>CUEyt{uL% zd}hMOi1PL}aY4((46l-x0THQjQ)Nn}M2dCHq@~;cvi$AdpZK2n-?3ZyN9QKpKfYgJ zpJh$a--Y`Wy+3+?Yx}#n&fw0Ey3dc=kFFOxnk?4+@N}-Djpo9N>_ht`KDam780Tj{ z^lz8vuTfl(u}}CzeEWlJUv*#4_4@DfK1Z~AYn|TYqa!D+eL6eMVwXgIcG%{XGt(tH z9&OG!FC4aJsn(4*rCt?PrK@-QMbyag&AID&X>QietIIxGF4MOM# zb2cAznie_f;XGmO1D6*!Eo@(Yvb|;X_0>^}R(BqKTv)LuOliyA2&d`i?LYX>|DmG) z=J$UFmN!41|4ym9aG&Q-_DAPO{73R{J3rDr-}fhX#UGz5Hr6ZjTh{8;L_U_6_I)^? z>-3_EYL`8eE`2@{XLcoTYp#3r&MWV~YJ54*uhT2?tM=@%h3BVydh$neTEQ|&%ft`- zoNqT?%?h2SZ`c>v&=)(^UEDV$LgO@}Q^l_dtJ@Aee06>OtmN3rb1elCHL7U_ed$Lc z<|(gP%;Q@XajN9Qm4$v1Im%}~PT6>K`qj7mIV&G!CvFIA)tZ{+)G8w?aryhxxTW!) z{~4Ov>JJ+4W34~vX2RdR{-b={$M=W%yW=dBw|Z;hnu4;Rl{a z)(fQW*yF}*a{A>XgHvn8IRlO*6cz>^Nhs#gjR;xXec0=IOP2dA!+GjlPi^)ao;8U0 zxAS^L&wS$(hEwjTYo6UZWn)Bsc2vvaxKe-eb-F0vMqj-V4S>>BD zPcHjqc+{yc++XA1LxUeSHXE;g&N;SKHLT*!bF=lVZWeE@i^naEx-ox6qDax3`5a4S zMLh@E7h~-}UL9P-wCITc0qcb=rd7tTLPRmz#1Ve%iBr-rTGkF``n1JqaIo ztSUH`X3@Fx+ObEAxwbC*sj&FZ%l`}qtN#c-*nf-rAD8rh29~)03{8PGb|31SOx82~ z@%_8(Pvq}}n%W=L5C1dpXGZBwU;V=1$D-F^AMLwJYt=orY}>T!N=@#QEY#8{mQKJaP#Tm(}f=%n3^7b)JH7&>zZS2@`v@fSI>G7Cf9Bj>n?n@@2UlkRwY-toNn^iRKH65qb8$enS0nzV4d!Q(oO15ZMX zS5>^4VtB(dp&)`!_QeZstluWa~{aiwU<2Tb%d*ax^YBh}!H;rE^Yw(a zPJXmZl}~T|byUaJ=RRZK!noqY!Bez~0w4a-tF}=-d}wc07ggLpyr?>Lc3_|T?>&!YTORS0i=^*Nl?fAW{~+V--nt|6 z(MwSOf-QXN@p<#aWrO67i~LAulxf#GE2I6$P~gnQsTxTS+g7&6NBo$xtT$&~oAc!4 zed~2T8=c(Dr+t3I53es;!6#Qg+qr+sVz0dtkF=9sxLcmle*X2-ibtA3tv=hemUkY$ ze(bQYW#YH`?D;=b?GOHExRv~^@kjmdbm(-{8h98Q` z@7R<0U|Cni;}85t-?LYIJ``v6f&HjIo5SbMMVD(_A3j_mzwzZY;jB+Dwu$}nt=Y!T z{df9|XOZ(F!y=+?UXzQsR{P=lZQI|b|91V8^>=T5=Kgjo<{!xq)_2!g zXV!D=(fshA;ep%Sg73O3U+w4o$MZ+(1N-6s4DIveKd#%MCu+K0>fXz$ZQIRnYiX0#A51fzb{npq{xH$m@a)RJ(FSLihiy|fn8$o`SNzQxUQ?HAr2ec~Y~yar zBckaScs#8nHoWcZW-p0-Jh_t3;sciUt<}0Avu^j%2b*3TGb!knKI>I@Jn3cd(}+8< zQd2UnEDRSsD-m+|LG~$8L(91Ec+OwVkKVIY7$2YIW2N73qyDg8@+LoE`AaIc zJ6+o2x-`0?`{1p2^B>LU{Lv=On{@5nCE5H#_f#*LtQY)I9_BIax6AdCz4qak^>jSi40*cNO=!NFF@H2`=Tb>i9zStWc5lI!^{nr%9e$*F^3qzTMN_plOm2Csv915f z@qfJcTkW&w|Ik`BiI%L_wTu%Zb;{ zul@GPi_g*wdiW>K_@9OaSJ$8T6ZE4$^LO}v zhJ$D7bbhS;$Q-f#!}K@p{~1_x{!ZWH{xBweUSBI^vO~Jv;D=9~QN_>m zyj^EL&3w3cs#f8lYe$o{gFcEgx|yg(?K4_ddN?Fz)uUu*{)QKiYHV{3ZEwHB+SKG_e#>WAicf?$+;}HO7l7j{A2yX_pa zZ;u0aU0C0d&(8uvw$3xandt|#-N>nyS*VC_+)7(qWE_%kp&pGog>)1wpk>$D0>eZIo{>`GtRn=M4H~2_+S7`bd-2&N%h|!7~=ifD; zgD~vVKwEkaa_(cTyBsHa<*TmT@v!bA|5!hsZ!vZKaQ(>pRy(t;+o#<+e(XO3@1L+- z{p)Vm*DB3@Jn4SW<75O?h_a6KK;38*6t&zmCKj~ zgSmST`4uhI+VVJPw%1aw%M06ATZx7&lnE1O?O*(+SY|(C_u(&>j;wgNaR-l|H1~|u znNwBW4Ne<#*+(2q);vCc`mNw+EibS1WQ8tS9k9}C%Z3|0aa^UUO~)P=eEk=({Xauf zY~2O(f5MmQBq}cd;}-nSz^e99{?J@$|I1q1_K(liExZPh&TOr^DKEz2iTgKT50tD|0g4 zwpM-Bc(~H4BF1`cm_?RIqPp*1j??0l(kNZ|H{=s}ep0Osq z_P2iKKa-Dfo3k?){Rn>e{NV4~XO)jfom*aLaxZLhdisO^3=Q(UUuUoMe>df|__c4J z?wr!|F8XlK_&4{#ozG|d3Dx?~@Ors;^5>mFhaP0DDYa2!GyObgy^g2X)|@)6y?nMO zKV?bySWV5TOPm<^%_QMjs|J7M56y^?KKOX`rR7bB(;~il zvv(bP_;+n((4mBt&vu$iKb~57<tfjqq zw;Zm~{#bu-t@>lNi7S2_KX{M*cdS=eU!9QYGapr%yZ1LEVSdSL6)h=r=H8w(-RA4 z_PKU`o7i&CTKVYp)l<`WFE7t2;}>M*_!RMMdDp>5tJC;(j|HCjw8t)UW?Qs!z*$hUz~-Ow%Cwlrv&RLJV3TBV7WHQm2K*YPRVr|-X= z{;ooSz=-{5xc_QUmW&3{`|EO+^Ez5mgNzb&_}9^Kz;6T9@s=EHG@ zAL@H*lrW*9EBnH(b~1)z@w}r!^*0Ij}0T{ zxW=u1DE>#--{HbO>mUB#7W`cSx-6<+e!Khe{=ya(<(}R&X8!iIJwdCT z#XHuwthTW{-BHmK%VWnb*tODTJ$Lug8G)xBdh@z-1{*DubmyOuyxgnDuyUR{+j9Fi zKhh-TgbC}eRPQ>FxFR_QxZ;=OJ(HOE=BUw;sOPnr`{ebMmRWQjp=|R%#yRY(DnbkSk)kh4+Djr`8J>_ILb=ow;VW`eCQFK56N_i}v<0 zGf#XPp|!`oV`WXAqK22{exYZTexc3ldqJ12>g?v)*e~2OrT-0o*oSL#KbAlATmAra z3z5jA)1E)(fB5$KaJ@hczu9_~Nw+fZnS6LME4}NFrrzE~XH#`1Ip(g6f62f4rMTE6 zYsEbqX0aLUs;Kdtlsa>nwC%$?uIV#Ve*B7@<{vKTchCF{v_cqK^tb zecN(tPIh2%?~>)xb0gXE`ww0@S^UZ*b=tETk*PPg>X<2+6bc_mezD8qM8JAUw-W8s z+#OxZ1HFV72OeB5=@e!^EB=QX`yZjx-@^VgG$s9KIGD80=#RnQ2{yhT7az6a{&&Fp z(SL?MgPOpP`7M7EQy;_&{R#QIXv_2;#t&_^-XEUF{2}$;Y~Aavc9Jztd$w=BzHX1} zn%Ec9q|z3a*KGE-eYg2-isaoKcfN|&iGCKA4?eB=eWI3)W+b`K^BJ{?Pw$ z`SJB_c9uVkKlUG-C4a=e^}f&^^OY6e$K|*`%C6jX$;NR()&&W@H}68_w7VFFDA`~}SI9;Sn>4AdGJe9sUelEM!$em)6}~?3xX`jpYnm~8VDNhHx$0UatAkeh zEm8H_%Ht-tN9*Coh!|g~sRlpxsHshjG1KM^TPH8<1={^?e=MK3{-E%l+z-bed|Ufl zyN3TiL(|HC_wRGoC*O^`9D5<*hwSq6zpZ|(KXQ-rgLy~VPV@cz`^0MMKeit@8~@n+ z@O#de*TRD`<)pV>{^MOaN{8-X3vHD>3-t^RqtZp~07e8L zC(M0fVawU9y0zUJ@M6ynHeCYSA5QyH92w*FF+x|MLCZNVAAV@C#o&jItc)EuZ`~_+%Y=e#bLf zW5L## zGO0Dj`fpb4taa59=X-LqO#e`{TBYWwvXrYXPcGp+=<*GC-lLmYIelg^mR8*=YOw!me_Xw^E|_q&BxtErx%#~ z5N|GsY+mlnxB1p;r86JO4<{&huIxPM%{ryvTIig|cO$MZxG$QJ;Vv02?k`fK7w)ty zd}_hjn4}~186S_<=|A$Sknz#}Tg*7=q2Uk7OGh4Wvvb*V<)g3blyWHT+Fmm6mS^r&_0~%fGcPuWI4!lB^GdkouH~*$OO>T3 z12wjD-rN_tRAak%+LT3aR~9X|&?=gvE^)Pe%W_TEqajUmUhce{t7@S&<+=YX^O!Hs zrB}LnJl+3r0wo zO0TZ{HorDIzcR5l)h0YFd|G&*&bRGh(+!Ld7G@VRFS+*l(0h@MRwt#6jArecu+nR( zS81YEY38|r)qYD-xu(2w@-uGrIH~DYIH_<-%9JUSebr_u&3Socx!+RBLrXOe885Xe z>REYi&Z0T$et~&LEsHMqEV>gDmAU1zZirZMobiYBmVe3>&PVO}|5QKRD}Kz5{p0@j zt@Al64j+nBzPz@yp8v<}!*Yt3-sUmQFSxKYP*Wh+AWsZEjqKds+E7u zUvJ5dgBSYpoBEUmg9X1b(vZg8qPWzepdULgjXM9^1S5s zgSA0x^OL{ck(F@`pO(DTX{wdr`ncBk?A|`TkQJAf+l0!Tn(7%Gckn*1v;M-SU))N2DsvU)EwM-T|%~RXTqgqpR^pSyu))!@Yo4CTh z1J5jvX+F+QjnGK_>B?1-*nGNZk4d6c?t@QnY^I4#(^`{t{o9W1oMFXB(@a6$BtgC7aM((x(hnA^N;Sg|CE3ndv{9n+ z^7^>>s-b#b6+NL=c_tq#R)pUQT^h_Bue;u_O`Wl0ecMrg?yiOIf?gJTWL={mNIseP>P|5N+OQ)&8Z-H^m)_G(tL@E+ef0_cj)WB z)yY}1U(C!b>_YkVV~-3aYS@H|dkP}M_~tR|91L9U*T%1Z@bZ*p8-DnhN*wByIJM+? z)Rx8anH}qc)+q~GZGClRrJYtpR>-PHg`8Jbb{q?xS`(%&7`07ZFlx#3pry;B1%uYQ zdI_%%3(0T`T-g3?QZH9P&yxOyuczDr#|M^ZN!t^l$V2F8a^#;E{ZT{D;8! zj-Ws0v%i`Don~$yli><>b|EjNsH&E+6Yd1ka=n!KWo?08HF;2GdeFVY&>K1 zPw{yAjheE^mTwVV5qH8YQ|HJ}58r*z;^B%%hNgzX^Fo^rCD$*##Rgkm!1zgR`)|&= z({ajwH`gftXJBQzZYSx!^54~eOg}=4KO`Ug&mi<}kLRP~-3}i_@1E~e-?8cPANjvK zY(&M@eEf0vs8!`h`9I448E)UdS@rhYoKm)}6_0(5UTrm+@qFU}zlhQ!8y0$71?I)a zEN!0`8YXhz-e@^{u<|K&RqvbkBBXMoZ#_!xI4|io&-Q7*xO~>9s?BSs-#w+(>owun zp-(+B$PO=YKJfSaVf`q6DBt==`LTPfAHN^|TYXs0Iy0`6?^Rk7fd3_%nSoX+9N&MMXs@`-g@pZ_;j)iZh*sc+I>1B7R*E48wSculj zi@(lEb9VPAcOOjDzVxD0X2Xs%ydFX8n~q-&*;ob>9!=l8nhcYN)2v$ZV$b;ZlzgHJ8AD$6394kx}yG^mh~HP`&DV<*n*H&w!GZRC|B zNvn%?{WudFbz@I#)Q?$Lv;Fz}a@^F#!5FUS3w9j|T?sl;IPuMj;L@y9MIi-W zuB&nx7B2Pl$}*@WH>yeHI)7Ga;_bp5>O{|okn^~P}yY!0cT$|g~GiFIXzAvrP zxz9ZHuJqz{MQheDuB%BC=I=k0w83Ik-F5EX!`BZbWfuF%UFPpts%5(J^P#{wl`qc) zK5JQQaqr`#OpDh}TYXHkEV_)ItaVyzb!B{7>MIoe%TdWq<32jG3P4h95e|W*vR>`r*fltdLiU8-MHx%WN+xwsFnLjXM(>HDjxMc2L1; znSJYmK8C1#xN-97)Vu1@jKPxaB^yNzzA8JlYOV||uBfpS=RLC`;lq>{bu*5N6u8S6 z9GmFOr4r~Wq*HiQCQDSg&y+Dx&>_T?G1P&9fnllTsU=G-PX*6;^4#+5POqZLdzNZi z@AUHBcDp?H?)_k?l80UbOT7e^`^{1In`>1V&}!kRaY&#gs3%cksl+i&jU|&jwfR@- zpq0$bpDrJb|KNK5huVLJ-a4Hc*B`qd>EHbK?9=zh;zx9)ADutu-&XJ^;>XG5|IXc) zs8i1nPY%4ar|@I&w~Whw>N7tGKVsX-w~B9jQBB~7@4*|deEpek`Zw&<@2D$VwO{W( zm38%`9OKiis;;RPcl?qk2haZYWm8U_UQfZ-jXQmHoL2kmA6aG4swKMNVylmgW^GRadl@vCYpL;9;6swM;(VP6XQhw5Sqo~>Zv5fn$1d$OO`E;<@U=sa zK3rX}D)30+MvRA`oM{~#Zsq=;{<#Cf+YxPC@;+&ON z7f1D6^$N`l=?-f3D(*?=Ji5{?(AVTr`m^oeMLD3`1gh)K*x7uDKO)~!&sw@$`hDxJ zXpwkYg`}P z=gN$FJI7o+Y*yOB)Xd6ip1(7)HXp9mJoq~%mS}=_3P6uYNlmrZ3}KcXE^V^ z@xsQVZUTK)tvbG@GmhEp_}=B`6_NCiCuOzOmY0Y6l#Le8NivA2Dme7?M$dI#J|Dfr zX#K-(^MsZuv&(;%%d$Jq^w{&k%L~7@N#CrSd560>-(qV<(2K(g+p1eCbuT?wT&ZhQ zcv57N)23V_m7-&B8mFeXDNdg*u#ulXHc{2hV!7L@!`_0D=lNyamA@IS=PF(vR1)eJ z9%k~K^OShNoRllQnbr20{-9THMFTHl@lwtBOBm*++Js-?0A3%zt{zRdvkdDyQl5yY=zwo&InmhAn*Z1EW3L zdbPG1Z2h=no#$cUu5-pZuVrJy*LN*#I&JjEM)UI0){_>+n!Tx0pH$W)i-ta2`DkP1 zvck@_y=!}qKQfMaZMeGgjA7t6KKZ)qk{4jD76yz%Xyujuc>Qg)PrcuLe{1-G^|!+x zsUJ>$q<_o&TkZuL_lNtN>nvs;jWgJ~>BF*_k5=aZUdc?2Tvj+YA@k6*^!X_}?BvcA7Im!+s*Gb7oRMVk zrQp=2l{~!pKf=y@_`0z|-?8{y&A97`l-lK>LZ^^0845mg&_Ib_-K3mjNC$-kc&RF-1X3$zE zi9KpcJqv?+Q=J9lrkkXG2$^*8(=yxA|P zRjT!HqeYFY)t0P-VGErFz5Mu=$&0ohezf7!($0l$YZU%Y-=Dny=I?J-AFg-pG5?@` z@Yl3n^CSEs=O6cX%9(uZ@2$!I=>Mqy$bRwj`Jxj(@*j!s+Amz={OEp1oXHiPFFzD6 zmn?q7FL*!t#jX_3)PHU7Y{znxP18GaU0dtst~qFrh?Qy!yLD}qC=*0{!my3CnX`g*I@RiVjQa+k_i zY8;-%w`6(n^m)Zowyo`0+YwQ5ZKYN>Z+k=(=gn#>!L?DlmM`78HdruprPt@Dh0D*p zyu6g7V)`HF?f)5ABL6ciX8hs(pP~7F=lwr-!=5SrXApS%pW&cb{fh&2LjM^ae1BB_ zpTRtYq4z%n+Z&LCWTgKa<_~k&SUqFwA5|H!B)m=icx%)4#oF4;Clneon7_V1u#f#i z|6zTWANCLTgNAuB=Lvm~Km4D8yQ2P}9oL6--Fdnu^}H4ShjxW7Ykzo`*=uXe+HJEJ zzZ5f@RolbxNISb?vE=R8nSF`9XE*bdWzS4nom?z)TD|aUk8Mls;xg_}wJz3vm(69m>e!N( zmsSUfOgD`@H0QZg;MLC|Q-TA0HLXuBeYfw-+7E{xZ$HT2yGp z*GP$~KlA=GG@YtH82Cs0KLg9$zkQ|u8TxNc>rQ@L-*r#xTJArY8ipUKwYFEp=9&JO zz53?8xPxXpepS1#aD4EdGgHi}y>m~f?V4-F_o5?i{m45WxZ&C!_a!m<6K7mIyZX_m zeew_Y=oIepp8u$B{j|jA&VpUNS_W&|7Iz=F5fi(y=1@s`&!NPE$UL!t^)sH$c(b47 z^@9&rH%k0b-#j(J;Off9pnJ+RQ-1ntl@_k+jS?}mnDwL6YaX}m!K+8^^%Pp{JhV1y ztE`U8hRQTyqcaa%j_u*UvQgfuh5>X{*Ajc_ef$~n68m%R|Ij-BHv7ZsZ&QD?E{v); zYbR27>KFT)&mWFIa6iD^FA#O}byWUg?|$|l-4C80kxhQI_I%^hDKDbl?S2$5?yR?4 zDE6kw_40z{-TMC~o1K1Pdi5pKvh8R}NStf5h^;ziWSt6fx^5WZ1Z~9YWaHEGWu&K93&z`+; zo?P!VdxIm7Hfv2a)(Kf`lcr?Qe|3YXVesh}#|8bld3@{D|1&h@{bxAnTc3HKqyC_S zozZ`WgHrz)9xS)|&(Ktp_&cD2**#wR-;vDH zn&`?uDv1;Mo!_PR;De9gk5vA4JEaQ0jJA~@-qtuj?mGFmUnphfIeTs=3!B%ig(52o z<@`Obt@oS9m(Sex@7m&y={A;f`Ua<7`w3Ne?dahbcq%c+EVQXl-eh6ZZPUZa7S+;| z4hx3AzG*I;sP*Vm&rvI()opVME8ghZs3rQf%#Bgsx_)}{2a#!ZbF>c2HZ(dt@Xy!$6wQ62STWA2C9hvW<{sa`Pg7t=qQFJ6Dh`?0+6 zOS9{7s#g|Yn{?Ul>Z414)K|LAD7eS3b^OD9(Z?TtR0%)o(U*Q)5EI+m^K#EAOBRC} zQZf8Zhpzm(vYAINdRoBh{-cjqCT^Hn#x*bb=*~K=y)}mg=RRC@JWgeG&*{(SxDH=C zQj}u3o%wHe`-Uy)p%2rKh*Y$9EIw+n=hpPAk6Wgd&I~yG^oPx^sWD+jOMSXqWV1vJ ziWc?^}sr)&9o;x{l-gkN$`KO?A2- z%$xG|ss6iFzs+pvgIf7Ved|9s9~Lus5q{~1_QUd~Jpun2KD51>r#nqwxWf7Ht!wMo zMrCuSKjQC@%A360zHO^MS4Dex^X&EwJN79beLiz-)m4KS!9(vPd}3>4vfPay>3n@W zkE>FTU0%mbnRUt`(~RU7hnALnyfOdHJf$-kf%Bvl7B@Z8+w(2Ez39)PUL9GTa^XUK z^DBzob(b|y7>It5xZ@^ndUnH%m^5kG&ZE03^55E+v4s}=h?1M^f${ zf7}0Ct^S~oeKLQ8ozdSF`xEPbXqvw@{q0&4{6qfX+2}{{ef8=7x5J%5%O4)LAOFw5 zUJ-QYKST7#@>Ux|@x%2k_FR98KYTxWcBy;$ii)WF2lpvN+Blalc{z`#@4fT<$k|7} z{YTfW|Q~tGA4hK#3InVhEw4q}Ce}<;+KSuu(PoxMNmx0YJ2%~`j#pY=!g z;aOYX&0Tsw?#|0;@uBll4Nq%5Sp6_7!QzG}T zZ8~$Bv+vZ#;vQwEed?^i!p+}yNd1WVT34=fJoMAw%pW^&QTOZC_fTtbH`2RX7Rq#JP`v*_o zOUM5Sg4q*zzD7DSCP0WW6zdOv4TJQWFE)Vgg@fxeDJXQ@Uxj_u3iSurfBIL?lXF)^I+wp>pEJ; zmTdYJnHSxA_;N_?)~p-#iCQ0<7rZDb{A#6rC}+3nh*4{NickbT3b5?Zk);&SK zCM%_k*ID$q$#Xhw(-w{Eljdz-Zgr!_O=*qBg@tZ&VpfH&jauAmRr2zvrC;%sWQk=@ zE`^&c^;%oCN+Wx`b`fcK^ z|8)Od+0Rn{U|szO&+7Q@d)C+OAIzV%C!VW5qyM)0q5Hh1yX$X;z54TGm$ZGm9Q(!} zjjLi_ocw5+w)y3qRO!JNht-V zvJTrFxwyXdYjF-Ab4NwidLDnVjh5f}AJuPLXw$Y&Sg`BVrk%$bXP$~UbFSx=^J~el zM4s&yr#@wceD*Q*F|+U5Xn9PmkDt5$@FV+e{6AFxGraxJ@ZmqhKd$uOVt60IA6j|=JwT9R0>W8hG*Lqf7_7|O= zCJ|E>+`H1vK4f+8fuyVlS=SHx^LMQNc+)Ih=h!^6J|%;tGoD)fx*3=5G-u_G!-9Tu zWx}KdIWDj749R#_nWoJ+`{9PK+E-ML< zXRN#VpJDUzBkym{f0VcXBmbd!+&`8s&Ae5%@=<=Poc_)a`bTV;p1WS(GGF+`uH&tH zeDiawWv4A(_Ij4u?8+xuR%I&}y$U$2H*@XFsCknsE0YUPb{}#V|C(7HwIw@YEpBJdR$)bRI<@z#kHk3n~vFtMqc@5VrcR@abtyz zo4lapsi`%3=DgwDU5oA0txA(tU0545yX2Kq%%;NJgQtZ4)lYx0{Eztef1IJpcmJK= zFSf`2KLhK6zZ18lPh9jv_P0~k#6M<#x73I~+>w4YPx0~}>5tQ%)dt;v#QSvW++#EI z>sS9+9`teRvxR(9W~DdQasMcOo7H(U-1dluMfyxto*d1~-;K|-&*zp zAYONL|JJtI^_dGR`oBg0-S|cPhwewI(?_l+-HFbK5?lJnQumMUqge0Y>eZDd_WaJP zBPzZJZrZVR&(05iv!AcgzU$1&b8PE-<<2E`~K~(2w-#&^w((O zT&@-2EHY`T1Zzu1e1>|1pMml5wMEGvy_p-2J&vio#?RSt)IvS4w0*JFI`hrjjat{I zXWu(_&19+nt*cADUg<6M2!2+z;`2$jx4Kc```SOW{%2t8{Bbv^UN-#fqj^vB7Mwjb}8&yFe)Z++O6?OlDA-+wFXo2#cHqiScr z*|27U_uCK0VxzS_OjhrWi8|^nKP%-&jL%}%z|f6ztPgM1N;2mB{W))0a&(v0)q)=j zEkfsdOYDErg?frQ!7$u=)6`sz3Gfr|JEaJy)u09 zlOGmLF}U(kG~;2xmlY2;ybV~)m;dhBw`<(5t#@nBxE7s#I`eIwQi-RKhn`Z!(%wt1 z8F%B%Q&UP)5(-X*Ot{CF-nP8wbTN-=YL&$rK7HQMD7`PQFRb*+x)jvCC*|r=N!K@* zeHY8vWU0MA})yrUE({iqopW*i3OCu-X9^q$YK)xLaTy!Bf?D;$E^Ym}{ zKYaf7<%4*(AIy*RkM`ekeyBJ5!F=)kJ!?$!Z?1o=xAjBzk*Kw=U+n7ZC^;{fRpq+& z(`zfK!z=ba2{RXat-5bvetseAnT))IT~Frm&Go61HYhFRS_e80>`+g(pM}?yk6#N! zS6yA(zJK%TjwPRd1so2aRJ_n@o8BC$KD9;DeGG%!_=TH7UhJxv^&{%@O0CT6EgvQx zSyi|^>{Z}W`!(l6S5{wnb#9*AlErTgzATkL^ZrM>_P4nI42v)PXJ}gWpW#u-kIVlV zX1;oD+5AuO)Zgj*UwpBDuxkI0xppT18J<-&@Z(U=@N4@wv;PcDPJcxHcJ4F$&v5AV z2l2Pkze{TTukU{-biGFYKLf}5x6Ho-E0#Z6fB4wu>(4K%@3`{xL+`iQ%Ome(hq-&Z zTw1TUbe^_iX{k}v)*D-QY=3?Du~y=TA8$-FFU%?Yl5t_R)t0|Yy#f|@E$$9FY-txI zx-^)dt9ZS{@BG!Lw#k_)y9;-;#`(DM%~RXPwC8!8(CLq+h9Qf+)~r0V=2gPR3d!K3 zPF6`8S`{a+_DcTl7WU@t*u2tdcK@rdMY4&IU1ID%|J5HnP;hSkhvM`?%$HPWwGWdfu$T(cXB!ZGaS)ArS&`Ww|MX4DsJx6 z{x_ZW>X`F{uI=gd^Ur(rXl0VYj;tw5!y>XuKK&Ba2wWPqO>ddkq2D&COYQW!<`x`>kf*Zj~6`@iqPPx$erm7_&gdAUYU;1r*gvknZGUv1{LF-_vmdVP5Bj+12cP!F=SI;L^$+Ja z+XR2~j=!)@mv?^G`*r`MUzVFseA&77X6(m;XW`R7P8Ul~oO5wy&qF_^lFc!<`Q7Hc zI<%~GdSb!NyX?JFlC>g2{gxTG8=aFso|N|Chn?#A%;cr5D`%!wsyu%2JYtPM&xg4> zX^a*h#YMa#Y}Tz=c`oF`PCtF=;P&LG!k!hU)(IP&Rqbyp{Av@*lWQ|w`S?TOdD3P_ zg64mj`B?r&^0#994dK1^3G!SuR+ntle_OtiXV??`!Q1&G7y+Isq%0B=m~Q=bAGK~?mnhdrqr|YQI@}OSjnp3 z6%Q@y_5L$_NLhPtxBQ#N--oM!WWemGK^$Qd##{IBcGJ(~fk3BN2eQK50>l{x3<&f^!KUie%jb;psH*A6_{W7&Enpx4WE#ie5pKld3Q zPWq`GFgMC{X_d&!Q){)ZX8MV&^qTUNZMps1s(l&X4#Czw+G+jW1U^rAqyHZf?n9an z`ENb`R{5j;W0khH_H23nAFG2eFS+S!O44Z+8n$fA~@O+y1?WAL;x4&E^cNsQUEH=-E=KP0OwnhAh;r zTie}RV{&CF*OXLFU+-;g_QFoH7oJ<47+o}tUr;of=c%g3se+~Ezh|8jnv>jlc$dVg ztfG?DPJW;MRoa>TJGK8qfc+1J`-kTSKTdz+{hxtV{zv&o|8L44WCZ^%|7P%?p=rU7 z&u*7=Ok~xrT~)sPNBFn>pSs=qKb(5`>+2P>f*109|D+@C)|h^{v43y&?AP|P*^`cD zSAFJFKc0F;PPsERzDx7s;YZn5j|Cn+wO``#T~=?w&Xqi7v90s;?an-JU*5f1f7OMf zQKgE``VUX8Pg@XhvS8;jE&H3HiHEOdU0*JB>4@KwAH_T$Lth;-Ei6@gb(*;;qQ^~2 zcy9RDlZR$ct@#>zD1PPr53ZnAQuBX?2OI8l)Koq`%l@tA$I1`NNA`1W<>$?avu-|e zn!j_O=Pgv{Pu0_#7|h&feS%;Ogx)%ER1l*sGz!fmVl_6e?;n}Zi%(7Z>r$sjG zSQU3_ncSW@Zt4CK!}a{XUE>U2Oa9vAsWx@xagp=+I3>9;+@CHBXUAn{xHhom5Gc_hPel{^6@XI5FenkHi1CdSxbU zJ33sh>@i zDl95oE`E59!4;+Fn!YPmyIOh$WyS^NN7`8|4QubJadz9Mw#;a+OuBf`+McysCaWI3 zy8KATL@O!l^5LMx?aPDqTwZOF_~O!HPTylwH5}ap|NZHA{$lzmqW^o4|One_ZaCtWLqC%DhmwBc_x3VAP=>1HE)ZTs^;8*{huzvcY!``|vAzrFkOviIL`KXyyL$8YVlVo&U%1ccJ}5 z;}07znraI^@Si~Rc3BHoxOS?qM? z^ycne9MAY><&H;%5?wna9~S2A{`=N4VdcY(CCP5`yVq^z3|V#M!v#Q zH>~Jz(2<0{t=_@gv|o#t7JQj_Hg1~I(io8!kK*L!^7y=Z^inHe<=0z62Oq6)=X$D} zq48*S;>LZq=03Z}8<2hT`kckTp2i&afDBJE{;{q<8}7kGOM~{t&QYIX~!RzKg>Jy_0cqmw{N~`zNyoGIqiFSxLCou zmDS55YS&r!x?PPv_prw=esaa;!(WT%#B6#qyJJ;~)-tQ2IUi>Dg!4R`y3um(hADS_ z!n93}rC9cCyi)M9j9<9xNa`N#{y7h>arLCWNdJ)&SO0Kc`Q!)7Ig>Y?e9q6^w$f|y zaxI(iDHl$s_8v{jEcWJXIFMH97T&U2GiZux$N3dnMXi}`68&%2AKIt!;Xgy4jsC;) zQWf6e8$PnP*2FG&DX0G7+TNvij#e(qj$+%p{PwF|c59c%9yrf?wQuqA*yy;Z7?<}l z7kp(p&a7FscTX9&@U+K;Gt10+KKwYtrY+cf^umg@Ru*$~BLmlaWk-9>jqnl*zgudf zv)SNK+Rrj((*sv~Ys6BU4?X@cb;0G{7&D_DLlG_4qo;KJ=6alVyS7XI@bNz)$p<(6 zXE^9=|KRoh8`%%k8)iK|@=yG4rw!|e`bX}^J-_^Tcx6jHtNr18sfzY*9oKTde)}XR ztzr7*dY!-zsh7`Y1^?ap=&ruE>$d$#Tc@{)Yd`XgSc-f}Pc#=G_FP2S2M+%K^uyL&Z9o@wRU8tX@mh1p`$bL&fm zK73nq&;L=MSo1M=$;P8e20!|ik^IlV^6~GA{TXZXqc5Ax7tEN? z{m1uVe9N_26F&cEc&Pm2;^SVm?}y{Lzi{W;^4~I5oqW{%ThzRbyqh*hR-}7hH|<_5 zHh<~87}rmK;w{2XsZU&W@3i<)Q+eJ8SJd4s`eKf?=D)QG6EpqKP#m-`c;cnA##6l( zP02c}H`UZ{%~P(TUwR_T{VdN(8y^j*n6q1<@cd>gySop=l)0x}TN)%G-W_6SAF^`x zW7U?E8*WT*JECQ==Pv-1} z|Bn6Jt{*=w>v!tI>wUZ*x+=Ub)pNfH&IlL09e=x`?fgUYW*gJ`+J~9B53lOl#IJod zOXTCZnD=%ZBr|A9`rSvq^ZN zvvj#ER|GOLZ32klvLY)Zk7sNnj8$Bh3-{9W)z{kIipV06Rv zBmK?wg8OXh&ew7OT>#p%+Wwz`bx%!wrhWH(G4&s_AK8{4{?EW$$MWOx!+SG7d_Lg$ zVgBR(uB8`a+2&V2vKRaz?sld3+T3*&*ZtaV@w)wIICm)Z=QM5EIUnBI=vw`WotRuO zv&>reV6sM1QDkx)JA3cBsd_3aHr((?{bTMe8ZJ8Xxx^Yfd6rLWHk+Kyyw_^8PIBFk zp7V_E+NUb!UR~+kQas1bTDJ0xKn3eDuRj+TI-!3n-r+&eUZMX6^ zo6TJDW5TUlhwC<-3Nf7H=-yf=@kZC?wdB+^$+qZtmW>sACL14pI_Xf*k*7O+^0Yap zJ$|UQqo<6YbNZvgond?tcl@lGrU|u5rkQ?P*K=vD51(V-qZ(VTsh@f_8y-$9yz((< zY2#Uq1jCY#Ke{3pAF`VIVb7Kim3jK&od;{{UyH1~w9JTs_v4=-t8Nk zrmTFpIBcm^XklsXJfW87{P|InGUu8UOnn_ZHRJGPe!rNlhNdYi6Cay$hJ1^=Rh-$$y4}-cKeUuK(a>f1~K}!}x=~fzP+} z|Kk$>U3<&_fqlDqRn5e#4X%&$TkN^kT#vZ&CpOvULS|K4A;aW_&W`;7Xxo-yVq*v7S1u}5yO)Nm z9;=O8YE^kf>(il1cjJ>EE>G2x@QD|AtQ-`Q`bO$d$`7k4t2M67(-(Lhw7#dg)#}Rf zrp2A7jeS(3cKG;wxcWlt3xC27#s3U!um7lij6b5Q{jK{yL(}Si7v_uZf3WgD!c-~K=7;AR zi=OE&zuw%To)+~Vn54zKiDCNwWv#%s>wzQvu- zitQKnb5-~s+Q;(YUiX9h%sZPDGCCfPS;eE4`+`r*3b>E{LGw$&c8oX(ee^O)G~dFqm1 zYbH%AoS3|MO>R}*UK<<38$Fj>KkLZalvYLjNsB)!nPz5@d8qWcS-P?JR?bSk6mob;iKxB zj|ykJx>2JiH79t=>ubwdW={!xnKDEEt5xhQb%VWPbY3{co8!Pts zMxL8%B@v@0Wm;&l#x-in%Yeg|R!6P%2wtu^|AhM=$*I3Bew=sxJHI|h|91ZIsITe@I);oVV-=x1aI;D5(e+Irk%JmZQKUN=&^1VNiJMQJI_5J^pUe`(O+SwU&_3L`Z zR|4)LMYsH<-~VUWykU>w!|!Y#_VUQdb4L1$&ngbuwBDv^8nfn!AL;yE%br?I5tFJ+ ztM56G_}crH4PU;uEW3?eqSKOn`9|loK8AP9i9f>ElkqSyYK`Wll5DLVHMi}LU46v! znrCBaV*BF$LzfPOJ#6(BY&vv#!A5Oar=^*XGOiwcV87+n&&wCEbnT!$Jf;Tw|7bg1 z@hRqF_?Ul7{aeKk)87#_qCeVy+tgi%W4TnP@<-vv@&%_K-k1F09AR#7us$ul>D#$a z#{)LZx*mGr>s#TFEgP@>v3z7J^xgk@jph2xTV>l9y%Mup+Pd^g%#1UlJf#-FYnCka z+G^t`x7BQMG;imk_uhg|zMh)L-Wl~gwlaNjZk@ES-#V$SS*BGRW}IeKIyhiTGXwg#!qg!%3^h|yBl&JWk@ z-@N}#{C@`4q92VPu7At8{C3G@JGlz|$Isua{BZc&oF6McL_6->Gp}-seyhC1`~NiN zX~_o5YwDcsJ(*S#cXB1qvuoPeD7y2SoP!SWREIR#R zn3%<^89gqWeqO1Vv#QNlQ1i+(b?(*`i@TOreN~OyD)r-!uS{&n>ZFI!!qKvw$Npyi zXJC2upP?!2-?{n^zH@~i+5TrZoa_CF{pkF@`7(Q)?YsXoWbofAeq7(7{BioR^F47Y zyRPJa?M(Z~-=VyD!`4j~A6zZX_4;+)<8scz>eahR-?KDc&~Nf$o-lJk`+G^N56xM%DzNT6ck47|$zaab!=c9?KkbNE z-g#zoPq;wZjg`+NkLgV@I4@{%tWTb^dD+Sp2}Ngk)i&%b<1<|BBzKtCPxIoT2L*FZ zGfqpb@DYDmTO>k6KZ0Z>b;bYg{%82$Q{P~}ecR#>vycDNyS`7oM)>cd{poK@D%u~| zzxDiW_ha7a1NUX@B<^|^i=JD!_(t}uY2A->x#K^y?YJRs{ZC%`T>eZ7SuMCc*PAxRqxM6Yd-L*}}1E*@bOHX_BIO_*b z$lg}|%%GN?Ss{lW7zQub$%~x&s349p_df$m)nz-aKj}XlKQ8|E zn!eI9)k=C9G)>9$LuHv>Ym~*E?fOR^*8C}DpOH|%$xw8a&8*Oc@xs%OUF=KNDwu0k zvf1m^)r~hI4lQ}8W13kMx;$LGbOyyu>URphyBOoS^pXT@H&6I zp8KCd=EfKQj6c*ZE?;>w^Pl3SMf9fYtj?)`6_1C0Y?(?7b^mEpKhVZkSc+PXqc`C7${r9d(2h%EK^z=klyDjCK zyjUW9Y0#AAoMpjl!=@A(E)H8NzxF|~%(gu*&V{VnBbVK9<>r94`Fu{_z>R+6jE$oJ+&pf-En-jCcp+6fuSS&wC2q*;nZ2H#4u?d7<>S|a$!(@6KWn_Zs4F*8n0)edUY zm+ftoNtgJ~u%<@*(3Sel_n2ENg4(Qhoqk@alcy%KS;mapwAJdWhSd$3(_I$LY%5Mp zm0y+gBb(jxVxP6{`iSZOxFXlYfG%(??EfPy|4r<}*(JY@A3py>{cr2_w@ZJ!WQk4J zGI`IR{nos_PN5?2^ii?Ttev_#k3WPT+-r30Xc%e7r;P`H zbT=OjDme5o{p*_LH^YxUGcB0%A^!6BH@koP{4xBy!H(-k@wbK_#%8;#Kb$^hb-wS* zdd}BU|0dkhxu?AOgLr?9?}uNnkNomo?O%{rqy5O%`_T1S=UYs3U;f?xaQ0dKaDnLB z?QdRQv=YsHSkx05RhpsmT;YU8KY#m?i)-7CJ=|d9KKa4sGyD1yn~wx9jc4ueW0!BQ z*dv>vH6!cNRLy&Vc{avVEgo;KVbQv{K3L`4=9p&5c<#7q+MG70RgQ(8-fUHoBbP&X=A4@LTss*F9_-eoS`X`%&iGKdz6wSEo%~c`v(8blbH*=IQ08XTqgq z&utXjz5Jxy;$^oy_EelP%?Zf}THd{~W$D*hLC3tNM6Zozn=&;^B)BC14JU0Lci&2AstUYY&U_Gy<_ZIC!M z#c(x$@O=Kb5M^&+uYGc%1z+p6>{I-In9u&E`h)ZFjD7ZXm!kTQ#Q)GZ{SM9&e zzg_BXMg2X0G`l-D>5#7F!ubd9^V>KUudWDp-FCTD)=W3}u=qV4djXr$hn`QT-FN?Z zCoEO>^3A2u`llCKMe+r=oKg?Zy7#JA1 z9#2`SY3aGs%lA~!2LoT{xdZB)Uf{DQ&ah&{aZu6#2=r(v;Q;X=-+&nGW$XO+r$sj z;TtaOQ>zHNrhU5COP{-9+VQZRmMp)0VnS=U>g%$^sCg_1{e z*wk;jEtRS`pX|=xGS{nMu1u(p8dHnmjT$#~cF+t&+%mEFZS%S7#A|GRsD5~U(4J$T zaD}tW2mZtU?Q&9=_9#B+XR9c>5Sg)0=EJkjOxbC(mqi?qytBl>Wm)9&Y1O-T-iqFR zy1RSl^LcS=(u@WBk6bzWXqDE~RiBnU_M0nJ&}!i}Rmwyou+>T;$4stA(V4gP@a5(0 zhaSGXbok-R;KhCd{qvg-KKvk&72%^JYb7#eXUMA1wL!%zEkoBv?XCK%b^XYrLeb?` zKjwrft&MTh77SXZEEu*lYxA7lx1L#HJva~Aw&x#Io9U)ZH;Ku+dO5s%%hapu=DY2( z>kqKE+W%lKsEzi%@jt@{-?{vc|4skUd^BFTrgGK4OYyRM{6BtwWZ(Ty=hZ*CYk&Oh zJN~$f7`iWvykAj#=$~lo9@{0N`}S^ z$zEAG{lmJr4JC#VT~oD_H*5W82tSyxDlM|t)Bnbv+#IpUX%APek&|a{opkWnro(@e z)+w#|a^|_r`Oe~Z8Y|uA$xF|_*6ZUY&o{?lMpnVGw1{67IXWuOgG^Q?8Rz70{x&ts zH)yI>UQo%;rw{%!YzhA(nEfF9`2JgmAN9YjT~Jd6x)LnCz9W8%{vlrB2j*|}7yn`Y z*xyiNy6{i&kH|&m7p|Elw{>;J89yV*Wx?*E-t04L>*YQMto*vFP3AIv(NdkFLu^bOR@U4_CK0W zf5_Yx{rYO-(zj2enLb+RSQXSoj-&({*hmBo7-3VaGcnOdvo)bX3R31n?EgO+lI?;6PnB> zKAGj)7Ws5qdZqNGqe-ii3q=bfI^9CEy=TQtd3kXu%cLI7z=duipwoymkC|-vktOo- z;fF7Ye!W~FFAfRxPi{UGaNyy}#DWV2i#@H2LsmvDd2Z>oH0tW>YjeGB^!O>Qc^)s^ zwLWN>vT(=BpuJUFwL|7Sy&Z0OiNs!m{OHb2`frzomR6_~|9_J9G-9kXL^W-Ic>Mow F0stOiW6S^m diff --git a/doc/src/Eqs/pair_body_rounded.tex b/doc/src/Eqs/pair_body_rounded.tex deleted file mode 100644 index 54e095340f..0000000000 --- a/doc/src/Eqs/pair_body_rounded.tex +++ /dev/null @@ -1,13 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - F_n &=& k_n \delta_n - c_n v_n, \qquad \delta_n \le 0 \\ - &=& -k_{na} \delta_n - c_n v_n, \qquad 0 < \delta_n \le r_c \\ - &=& 0 \qquad \qquad \qquad \qquad \delta_n > r_c \\ - F_t &=& \mu k_n \delta_n - c_t v_t, \qquad \delta_n \le 0 \\ - &=& 0 \qquad \qquad \qquad \qquad \delta_n > 0 -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_coul_soft.jpg b/doc/src/Eqs/pair_coul_soft.jpg deleted file mode 100644 index dad9c745ba6bbb555427ca7b6fb448bc2853caed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 11309 zcmex=_85ksPA;eS`Ffj19FfeR8kK`XQPP5`i&FEFQx(E8Q_C~+(iNQZ^HMTPGV}8kGV^f7Fqztr z+yG)i(lrAEgYc4n3?lJ*3!K{R|8YOvRb$;Pm4h6rzw^T2uy+2W3kJRt7Exeg+W+Nd`FvWd;ofT?Qit za|UY$2L@LLF9v^x5Qa#GIEG|~42E2WB8GB?8iq!OHimA72@F#iW--iXSi-Q9VI9LJ zhV2Y{7!EQVV>r!lf#E8{ZH5O7PZ?e_d|>#-@SBm5k)4s3QJ7JZQJztiQJc|-(Sp&A z(UsAMF^DmeF@Z6iF^{p7v4*jkv72!c<1EI7j4K&8GVWwN$as?RBI8ZQhm0>7KQaDd zVrJrD5@C{MQe)C*vS4y#@@5KQie*Y?DrBl+YGLYQn!&V)X${jhrh`nUnXWQDV0z8; zm6?H=n^}xmky)47g4vnbpE-&-jk$=qj=76@8uKFNbO`6mk-i!h4< zi!O^biw8?6OEOC#OC3uO%Pf`^EZbO)uv}(&$nt^ZA1g1b468P)6{{y}1Zz5LIcpp1 zG}dLTTUn2?US)mC`i+f^O^i*Q&794HEs`yZt(vWeZ7$n-wgYSz*&effWoKuXWY=c5 zW%p-KWG`WFW1q>shJ8Q#CHAN6KRCEKYpP7;ZG4yb-tlwttMWVY$MIM3PvhUrf1dx10H=VOfU`iNK%KyB zft>=^1-=Rj3mOXg3+4*;2(A)5DfmK&T}VyHRVYQMMQE|mVWG#u%)-jT&ceyU&B9BB zj|x8(VG~go@f67t=@wZla!%xfsF0|MXqae)=xouwq7THF#ni++#d5^@#Wsmu6Z<7D zEAA+sD&8r+PW+PicL`|;2Z>aPE{XLLS0#Q)DoDCYW=l?#+%9=nibYCGDp0CiYM#_l zsW;Lh($><+(p}PcUA91WrtD$aH*#Wf4suy?Q{?u^ zy_6T0x0BD5pCZ3s{*{8Lf}=u?!VHBY3Lg|@6g?D66&EU=Q~a%@t`w@&q_ke?t}>Uh zg>stm6y-z8A5`R3d{t^xR;%1nYnOV>Z{f7 zXz*&-YZPiM(zv3@rfH#>tvOfof);E$_HOMhoVsP6~$k5BM$#9q9CnGJR zWTV+eSB!a$-HhvvcNl*((KbmnnP+mtRM^zlwB7WO>0dK*vm&!~W-rZE%oEJ#m|wRL zu?Vo}u{dGLYUyNIZ@I_vrn`pbx_JN&( zU4q>Ly9f4)_KEh3>>oKOJES-)b9nBk>6qoX#_^q#fm4ywR;TaIR?fA~2V9t4++Dg{ z&bbP?hPuvjz2~OnmhQIN?Ss3id$s!k4^|IvkBJ`FJ!L(UJy&{u@G|$R^*Z9s;~nfh z%lna!mQRt-E?*{JFW#Zr0@q3`VqAerz52zGb49Iu}6hP zEsOdZ?HWBb`e}@5Ok2#gSoPS7*pqQmaXE2&vOi6i}YMVMK^?90Y+N87>>9*;U(_d!TXH3g@lj)o}EAwNPN7nqT z@7ey@%d`LIgy*c!<;YFQ-I*tpmz{ScUoO8Q|6+l5L0iFtLaV~5g&&H%i+RO<^E+5NGCR(78h6g@{MVJzb*kH-ds_FOp5&fWy@tIrdjI#O^_}ZC>z_A)Z9?9J zYZL7!u9ze^scO>W$-a}fO;MQAHRa3H_^BtSnM|8MoojmO^anG1X6%@$GIPSrKeIAs zU7hVTd;J`lIh}L9&rO+oX`aKpb@OHCchCQ|AalWuh3*TtEmB)FZ86*8vc=Dqge^I~ z)MDw%Wm3z!m;GIyxBS71pcO|}ny*~BN@i96YNpktt6#2(S#x2n%i105bk{9hFSfpW z1H*>W4X-vPY`nI~d()xK7Ms^?QQb0UtMJyYZH(J0w|&^2vHii0$Q>7VdhI;4%X-(= z-Fmy1?@`<{d#~u;{(W5gTK4_lU$y`1fr0~X4yGS`d?^0V?ZXj=uN(?_nZ98v%e#ZsN3%f4bT-P1{?+w{zZUyxa2L;r*Ep5g(p@Ec*EWQ_p9~&&$7@YWzaxRNh(*VzmB7aj~v*c85GgD*BD)Y3|6jz@x!>Vxi zw7fu*;GE(zZ*QlNvi!)z$S})-tRVly{7NtF3e!x>LVvEPjKUC)T<@abP-9<@!ip$& z^B})$V>bhXN~5wuqbfslk1Xwsq$DFZ<5cYu_p*S>@|0BbAWM_9)L_5N#Jni3VCQnv zBC}NAY~K`5GyQ_XobVD$%f!T7?+ESme3L+P^BgxrldSX*&n&M1Ukmdv_q>#nhzMhs zjN(MUGS5PDE^Ws|?d*`WimHfmA7hI`V~eQ7qFmEb<0L=haL-&z{j6NyQi~9;)T)xS z@{*)V=OS(YFwexuio8%0)2NbyaIVBCXYHzBpVHjSj3Cnrf1})xs7(FDs8XX`51)d} zz%aw`9M7syZ5Q8UuY6zk2=_#n3~vwbf+D8^L$B<};0&&cknk{H505Z|lyHCJL{tAF z1N{mojT(i93iqPzA^Ds{r|LpSM z6t`S+ZNFku-;zQXi~OPrmmqhqN-krc5I0}1jO0ugGfPi{lHjZYKd+$Bu-u5uh&+9x zGE)GB-0)KG+zhuoi_j45;!0nm@Nll;#PnnXqbjHTD3c(U9Ji8? zsEV+#0zcOr$MO*Kuy9lVvc%j>gCG~r2+MSH*UU8cazmraQcox2qO8pPGB;PQvh38z zoI-Dl(xfos#I%s0ybAx2)bcPFqnwITpF;hhbmxrR6vOPI9PdiQ3d0nGAkTt=h$MIS zjF1pR{bDCiuG|cdAjbd;@38W;d_(7mAn!7BN8hNzjN%m2;3NZIH$zv?tP)qpByDd; zAD3)L;~-CGXP3;h^oWpjwcAN@e%imWW}l1k59b7x;JBV$(& z%Th0wQYVW5liZwQlb`?-FBdaEV~dnL3&%8*03S2QB5kK4ZI?pr^l(crbA#Nxf~0_8 z|I}P(OCR@8u52??FGI7?vI6&rf?)0JBC{lOgRHb*OH0oHgKYhv$kZIKY-exZ;HYwQ ziwcXvLj7_NSC7O%7q0)e8Jt05RE!Y7#Kg$N#KHsuEX>TzEUZw##>TTd!pzFb!otA7Sj))7%)lbZ zDx_%W$R-?^$gWfnAuRebI z{N?Mn?>~P20{M%Pff?d0&;TLGTMTIa5@cXvWMW}qW?={Ui;<}uq(G2`Rnd@5$T5&T zu~1masF6d&Y2w0-2RW6EgFc8R6KQ!#m{`Vr(cu+NC|SQA-3gL@3&uUiZ}%!~|7 zg3N*p_6-02X{>Lu&*H!R{=ofB%a8Rp)HBuieh7Xf-&s@r(JpgMjqra4j=HJIwQP&a z^CtP0W<`0Qn8n_9*Y3h6pOqY)-#MjI7MlH&{denEey@E-F8jCCkNt1ne$+p3U#K*n z`;oseL+XC}KdliygP-&XYp_4g;=7j}R6zOT;o!`JIa>O1z?*J|lH#j{q}U31&^J9O!u{|qla-H(fB z%;fgitfIT~N$X)n`3+xx?EmfXhvCQX57Ga)Hh=if@Q*9@!|Vs|)_$~qxNq}^u=vJ# zrXT9tN^9*7$6YMT%3TwcE%tInT=ea@L-D0+wmphi)?MW-FuP<0gJ#{u{|q1e`n%*r zek4B7*q_3GtN!tuc%l3~kq_VVRs8zT5c=cpy6nlX?n&&vs$JRo{N)-YN4f zESp{x6E?ljL`}QQb?V~$<^LHn-v7`te-ry#^Uj|ndC5BER}(Vj`5tbV{zz`^q94xT z*S5Upnd>+;Cu#qV&0D7`?U-?r?{>|WRg;~y7rAR$m(J%e<-g_rc>A$@u0I|huOH5> zewcq?Kc{`B_P1;fikv!eVb7`q*N??nUf!o$cgLRJ{=v5WY$meehsExTZ;fYSy_zM(>aOXAu9-@L<_K z;SavY-z=>D@c7~OHxqwb+^$GJG>`YA+}ee4Sr@Y8)F$1NE_b`M{(bJ+MZVUDgKjU{ zb1&~?_ohWw?->4duULOx{)X`*_TGK!ujRLeciAbul;ZqYH}hlUA6d2S57V#g-?Y_m z`Ae&yGm753I}5*A|19M-yrAxst5D9c8i0iH7x9o4-XZP=#{D;{6 zO}o_Je1E*3^@ZkdqZ*+-A7kz*evEHk_a`_vb6v%*hhP3PY&e~syDD?tB)jR$B`3vi zkdiTToKe*q&(S7ir^^eYv?uWwuGl*~5-+9mAxB4H| zeae^jXXbZ?-CDN&o5dNi`FT5iE4+)J962-b=bGCBQ)9S(9sid3chWwVx)XJhAGf#s zW3EUJxcucmgV2vz^%6hYUPpX1Tm6XFJ^0Ey+-iscX!WRn(_8w{Jh}rtPBR-`T5Q{%1)2^yk|B zXFvDl&zfyk>A(L$rG0*WpTLqyC;v0B>iytS4%{*SNAiCLx&I8G~!?LOR2lJ7VXPndvq>idBh#wzLiStPA`5>ycym7WA1Ooy0iBs z?BxC^{0Mx!zGYU*eExm%*}vSoY`B+Y#^p^GZ-2j~EO?o3Lav-Hg09rMX=9owr|} zbW<;9+4ky`{|qg4$Kth~Y5r%Zy0p*z8+l<(Me@AK|@;myXAPYd~F-_BUTKdJsQ^kv^_fWX~oj~&5AoheCO{=OLJkcCuGG6!tPjGf2;jlcl^!!2k!~* zyjUYy_^7}8pTS4b{Z0Smf4JRya%(t!LZE zpJtag?K#tUO4Rr4QHJ#Y42K^6U1k5`-2TssnfL#=%755VpVj}%c>SLfQRV*`1mmLv z9pqKeRn#LU?`EFhneOBhJ?cP^W%CY+M^JRpNt=Z`FY4MQ-a@7wl>ok6FAC_#+Pz}EP2lR6avB$N-j{YR3fkydZBo#_qlE93lv~p7*|OQsBlj^>{AV~= zwg0GnXZ+^yH-<}V4E`>(i7#Y5w)-RV;W~v2>Q}zXYkia6sk~SC!0BR{d%=f(|10Ur ztXbarZP(wMAEUqZUf##^C*_CmhtJ37Nt@L%{b;W>Z`)!oG1o~kn{VI7y+^mrEalFv zID1DhW_D#`O63Bx_fJonZn{(R^tbzehJ!9!`fsj_@0HX4n18UhF23PE1J54EML)`q z-_y?h;4l2@(UIGCGQ)ZWrRHw2zh!pl>7b!679;JCC^{L$7Wa1L) z`h7lT4w$~GJ*`UB7O1 zG5k~~tnQPq^tX>YcK%rTq580#;t#=fnf2UtiZvb|*$>5Y{+Racn_`veTAplO>-d-J z1RreL>B}B4>C!XFJSmq?Q5kFZT(E`%TWY0Ut}ocN?P|i-%X$yex+A*GU0k&;THJeeh4Bu0>Q1})r{M3>ubleI zoBmE(I4?VM-}#~qf7~w1993ZKvJ-xqyVQ^Wduz?v-vWQ?+aK!x5$ygJ_;>L?h0|*) z`f|k|@by0OzVUWR_TTiV9kF`s5eoNiuglj<)fUO{`Lttnao{{jutL*z8CChw^{8<~^Jkc1>{I!Bw>jJ#x>^xRP^RM*e;H zn()K*AN=@v|M-3gf8+VvuEP4U{jnc)N`JyGewk@9U!Y>!{eW6G>+ThLYF!bmw^vlJ z-)vMn`E5|$r~1u5*MHs}erF0ppsNT&_=Dqb1?zw3)Oh@7Xj=0_{#(G0+}|blfABv% zxAB2&`6IE_iz@t`F6QgKv9Zn+YhM0x-SdFU>$u|YWM8j3ZL{LH)UlgNu6?+L?B;8~` z$Xx9Dt*8GPzAf)GeVZP+@4D&VqSw-O7gxM0zjU^|QfvK*w#@h>R+k%HtL)9}b7k|t zow)j+;lZN%jq~69{E+-@?nm{eKZ1`Ru6k8aN{*%6QPxadDhkN6X zivKz{f8nZQ6S->*^PWz9^XA*4satxF?uq#scub<}#nZp@{|TM{?HpNm)wm)m{m1*< z2Pf_1Z)f|jij#PBNp(-xujrC3pX<)7`7Yq})}Z@rzOKl=qudU1${)(3uIx|dzq$Bf zcx!$B`rG}7?`i*-$$RwJ?COu^N6U7lHzi(IpOihjyJFJybDzQ@)|$Dtlx4DR_PVqA z`t7Yh=YKr>E%L|KNAGXNKl*-5R{DTEpH2CLddV7v4L|%$`a5oIy&~|U>_5XTsh(fw zPDi}a3;J~H-@R`~&gVb7UHN|TEtmHjCq?I9wBPij{a;g={SUqRf3^n#@lRucF!(XXn=! z=BAcb^3I!G_$2zyT}SRSCt`03E}Hx`YG2*oh4pFsoAz%FZ!+m;{FDEoX4bmy<=NBr zsa?$1DUCj>9D2!AJ1jZBdig7{qQm8>MYHF!T>EtFx5`w`o60L0p8sb^sa1c}H~T}f z$F3jy*Z=X|^Kt9fw@0rY-F|fc4;TK9Hv;xkCY-n@>3W$bXJh5br(4!dF~ z$M$!ro$e3!2mOD9Hh)w5!TzYzM*pMxPh4_4i~r$UVVB7PSH4>2ChiDt ze|u^D&9`swRj6%un>qJ!?TY^2w?AxtnBQ8*`@`-0fqDFUuIH7^c&E0@Tu$Yq+ww=c zZs8M8@Aj@;5#wL1e&%3^%^E?bMXWBN^0VSM{bzVn`Y^u7ezX6<{Y-UN{xdM!_&%K9 zHJ|fO=IT2?(jzv1?EhxAKHuci-S*v=x7xA?|8^;xZnpg__hFTdCaZU*H8W~3cmF8< z`1{-158{7B^^ePc@bC654*&R{;o!lCx%`jL%rpJSHaTb04}Xt&wpoY1`^@^rubG#Z zSL$o;GwrIJyn$o!YQu?>&WWr~{owxg_Q(GWkLMrcm;854esles$*GU>Z?4r@Z|cwD zx$?)O=N=#9dvey=UEsaiH}&sSoj~`J#ITLRcNgDrH?mosIbr#=ebV&@&Fz!lxBO=i z|B~N7kM&3Sny5bs+qa2*|Mm8G{~qUByIm(`?-=^7{rUZz>FgOv`*wCo&vndGYn2T% zcXi=>w14yV1M;`~zq$XNpYxv~`F^YTef~YJAATSFmie&0Endhb^bz-q(pqcx(@R%e zHHoe@Ke=bV@3xF&N8Uf&EB?-ZUTbkG(!uPX!qW9U{}~>vyuYF3*4>_bvAG|_AF+3B zxt-ZQYuohqD}E@QKJRJK}{ZEa2bbhUp`YrW;gs*>#|GTD6p+fml{Bd3Lf>Mbb02tUtx2XzYOcQj=JqK?W66{E7OfOgdWgW={c|bAZ7PvV>wT?tuL5Q{Nt(k z&v5L%&>!CPN9#M}nQdG@yg#xj#*_O;`cbL2{_1)mWr0a1vr^yQ-54G}gV8YYk3;xF z{XgRVk9+U!fAClR!2M148`j(8|4yhoA9Zg2?|>}dOR;gze+IX!5B9U~PnU0+&-mcS>iiGu519QbnP>Si^gl!Io>-H~ zXUol2ue@*ey7Qgt+`IR+w+h+3=`-<|7$_LRP*+%gFx1ZQhx;S{KZ4I6g}?Rxu=r?~ zN$CX}%a8RBzwK~4n!VfC+vnPrNUu%rw7v`6N>ec3QPlm}v_yXE^@I99G}4dD-!eb^ z_)s0!56cyGC*@?!qWar(YJ4A`&Aa#Kb*GZ|-|Z`37QEPW`~Gb9*lSkBaZ7j1w7YJ+ z<$j7)+598^H?nT~{wVw{^Pl0M-Tw6c_U%&YZ|ooDi$wf5e60M}{?4?k_wM^%c>n0? zm%Ch7*XQZ!r&Z4lvetQjc8^u*+B@1RdDk}1zvjj8uuidJ@)0|M58<7E0w4Of-fCK>MOoG2TV*8huP zz0mc2951Z?GrZ;fu=!i>uB-2bkH(37NZb2hwY7@ox5%|$XYb|u^vKgL_Fs}+bKc4} z?#|Q``O_Ih?d1MA{Mh(W{-N5!M|Zs+gsuGWpW#u@hP&>G594KCRmEPJ=rg-@_Z{CQ zckdm3vh&9M-Ba&|%vq7A{n7oK#)tGjBKhB@epEl=-^u--fmQe8-2OxU?e<%We>k1? zzrIhlBI>J6_QD@Es{Ng!Pq%H|UJ)K}_0bifdm;8O0uHx$ax1(36%KFzcmDq7?}y@V zmOu1w|Ho0o^Wn@b`@^wXkKTQ|bnJ2Ho-0c}ug`nFZ`ag!dP}EO%6YGz`82IOdFS~Y zE`~opKKy4mkbnFB(fuC+c&)!R{P_4FzFGV~1M42^wOL~J{P}Nda@WPZwv)K{F^}J~&V0L+-q}%dB zw0j<<9wpWP8EmvS*QYMg*{zziZ~n*A-~9hhtIzz;@Wb^#!^5Tj8Pe7>)VTaRZ2X@g z=|97v(g$y?(a{aWK=Pt%O2Rg{aH~wLL(BCE}_~HHG y_iguhF4fpRkd?ctQ!GHx2m)|V#6VlLq6zVatT1kUxw-;y}8WZ#XzX_85ksPA;eS`Ffj19FfeR8kK`XQPP5`i&FEFQx(E8Q_C~+(iNQZ^HMTPGV}8kGV^f7Fqztr z+yG)i(lrAEgYc4n3?lJ*3!K{R|8YOvRb$;Pm4h6rzw^T2uy+2W3kJRt7Exeg+W+Nd`FvWd;ofT?Qit za|UY$2L@LLF9v^x5Qa#GIEG|~42E2WB8GB?8iq!OHimA72@F#iW--iXSi-Q9VI9LJ zhV2Y{7!EQVV>r!lf#E8{ZH5O7PZ?e_d|>#-@SBm5k)4s3QJ7JZQJztiQJc|-(Sp&A z(UsAMF^DmeF@Z6iF^{p7v4*jkv72!c<1EI7j4K&8GVWwN$as?RBI8ZQhm0>7KQaDd zVrJrD5@C{MQe)C*vS4y#@@5KQie*Y?DrBl+YGLYQn!&V)X${jhrh`nUnXWQDV0z8; zm6?H=n^}xmky)47g4vnbpE-&-jk$=qj=76@8uKFNbO`6mk-i!h4< zi!O^biw8?6OEOC#OC3uO%Pf`^EZbO)uv}(&$nt^ZA1g1b468P)6{{y}1Zz5LIcpp1 zG}dLTTUn2?US)mC`i+f^O^i*Q&794HEs`yZt(vWeZ7$n-wgYSz*&effWoKuXWY=c5 zW%p-KWG`WFW1q>shJ8Q#CHAN6KRCEKYpP7;ZG4yb-tlwttMWVY$MIM3PvhUrf1dx10H=VOfU`iNK%KyB zft>=^1-=Rj3mOXg3+4*;2(A)5DfmK&T}VyHRVYQMMQE|mVWG#u%)-jT&ceyU&B9BB zj|x8(VG~go@f67t=@wZla!%xfsF0|MXqae)=xouwq7THF#ni++#d5^@#Wsmu6Z<7D zEAA+sD&8r+PW+PicL`|;2Z>aPE{XLLS0#Q)DoDCYW=l?#+%9=nibYCGDp0CiYM#_l zsW;Lh($><+(p}PcUA91WrtD$aH*#Wf4suy?Q{?u^ zy_6T0x0BD5pCZ3s{*{8Lf}=u?!VHBY3Lg|@6g?D66&EU=Q~a%@t`w@&q_ke?t}>Uh zg>stm6y-z8A5`R3d{t^xR;%1nYnOV>Z{f7 zXz*&-YZPiM(zv3@rfH#>tvOfof);E$_HOMhoVsP6~$k5BM$#9q9CnGJR zWTV+eSB!a$-HhvvcNl*((KbmnnP+mtRM^zlwB7WO>0dK*vm&!~W-rZE%oEJ#m|wRL zu?Vo}u{dGLYUyNIZ@I_vrn`pbx_JN&( zU4q>Ly9f4)_KEh3>>oKOJES-)b9nBk>6qoX#_^q#fm4ywR;TaIR?fA~2V9t4++Dg{ z&bbP?hPuvjz2~OnmhQIN?Ss3id$s!k4^|IvkBJ`FJ!L(UJy&{u@G|$R^*Z9s;~nfh z%lna!mQRt-E?*{JFW#Zr0@q3`VqAerz52zGb49Iu}6hP zEsOdZ?HWBb`e}@5Ok2#gSoPS7*pqQmaXE2&vOi6i}YMVMK^?90Y+N87>>9*;U(_d!TXH3g@lj)o}EAwNPN7nqT z@7ey@%d`LIgy*c!<;YFQ-I*tpmz{ScUoO8Q|6+l5L0iFtLaV~5g&&H%i+RO<^E+5NGCR(78h6g@{MVJzb*kH-ds_FOp5&fWy@tIrdjI#O^_}ZC>z_A)Z9?9J zYZL7!u9ze^scO>W$-a}fO;MQAHRa3H_^BtSnM|8MoojmO^anG1X6%@$GIPSrKeIAs zU7hVTd;J`lIh}L9&rO+oX`aKpb@OHCchCQ|AalWuh3*TtEmB)FZ86*8vc=Dqge^I~ z)MDw%Wm3z!m;GIyxBS71pcO|}ny*~BN@i96YNpktt6#2(S#x2n%i105bk{9hFSfpW z1H*>W4X-vPY`nI~d()xK7Ms^?QQb0UtMJyYZH(J0w|&^2vHii0$Q>7VdhI;4%X-(= z-Fmy1?@`<{d#~u;{(W5gTK4_lU$y`1fr0~X4yGS`d?^0V?ZXj=uN(?_nZ98v%e#ZsN3%f4bT-P1{?+w{zZUyxa2L;r*Ep5g(p@Ec*EWQ_p9~&&$79DD(1EE~E0YqKG74^Q6*}$fC@s;GD?RLJ%;^3@;4N_D;$$ugrEc3=Jzv^ezl7 z4Ar)bjPUU=OD_ydEDS9$H#guaNX$1Y%g*pCEUGXHD=fB5)=o@LGEVZhG&S;y3amo4=pN;OiDG5 zayR!Z$u#yTNG{h;H8m=#%FD|tE%4U2)DH74O9=>0_K!%@HYm;tt4uAc;>xrr3rck_ z3Jdlst%}Is#t8{nFOf4#P@lOp2ck%Z%v#{{43eNNJ*RRO&OA52J zEHCtN_u?|wPAN^xPdBy*_P59l($A^T&!{lYE7UJdjmR%f^)J!(%E|Lj^{fmtP7gD- z2r#zDE!563FUieKHt{Vj&4}a*4=c^`Ov^9KG%hHN%nnKlNht_7%&$l*POtKD$xSH^ zF7d2Lw=gZN2+z(B$w>DrNHj2UNlx_)EH_Rm@NzZa3XUo;3oJ?YbTvp#G0w_MF-tYC zOff5UGI4UsD#kC$jr1%Hw<#|c$?b&Bu^F^cj^ z4=*;#%df0RDU8srEC>(s4vgSR_Dv0O*S8GtuZT*H3M&q)DhfCB@yy9`FSkthH_H#J zOf@eFFfKLDGA=REPceu{O*TySbjirg4X-dR_b|@jGRZD=3AFIb^vHB7@Xj)I(hrUd z%Lp~{bq@|Huy89#HLOa?Pq*|bPxX(?^@;M!H!MraH}VfHGD-4EEcEe< z2{pAa^X2ld$V|)&^3C^3%XalO2+j&D%&PK^G7QSHC{N1JH%Jfk_4RQtFUztp4Uf#u z^$ATXboVPa@J!0fH84!d&5Ppla|w$wi%5;ocQc4`E6xtd)y_=}42{SrPB#h5_b$#3 zj!Jb652^HXwaAUAaLaS_G6~Gf%J2{O2{Q{ZiSjY#vWP6V2o5Rn_sK8_$qo&3&r8!T zb&E0#2sbSAE-ns<3U)Iw_SN>zF33qr_4aZ#^!4#AuQUqH&nhi7D)e>_;&Lrd3QBS_ zw(z!$3JwZz38-*1PB$vZH8lxNtT0N+aZL74sw{R*PBgRd$#hIHGciw0^osIv_sfkk z%PsQ`E8$A?2rx59GBiyL^9v1j(~k;w&Z+cs_A#qU^fw3$4>xd$NQ`g^a?6YgG4~5` z%qTQV4{)jsF3-x(PSf{FH1X#u@GC3IFDP~?4=*+d()M%7NiFs$EOZTbFLVt{^K;~RFo`HLaf~o?_DM?*^C)&rvv5wc@Cpm_vJCTfF?9AZ_43gVJ_bH3C&<^r1%lF7DbS%pb4KRq*&yO+> zc1tO7E#oqCNi*=*FGwmXNKG=0@~bS+u8c_44%F68s;~$RG7It24lU45%1;jSsPHbZ z^e(b=E{@0vb;}9!$_Xtf2rlPx&2cOBcFl1MGb+z1GIq&HNe%b6$j&tl%+4${^sRLA zGD)g54Y7!{^z$&`V)%cX!5K8N#RvgROpHuSEKDH4!pzLf!U_d!Y#i)tY#eN?tn6Iu z92}gSoSdxeT-;oo+#oi{5Jr$5uwE8UHdZ!}3excZ0}O&33`tB@%#2D5OoEKef{g!< zFvv47FtS422C8~Mn30K@g_Vt+gOiK<{}G0*0t`%y%*;$I%&e>|EDQ{cwTw*63@n1I zLW+itY{G$w>`H|qMvW5}awt1(JSZA;@q>zSQc)8pmzcPOq?D?fx`w8fiK&^ng{76V zi>sTvho@I?NN8AiL}XNQN@`kqMrKxVNoiSmMP*fUOKV$uM`zch$y26In?7UatVN5L zEM2yI#mZHiHgDOwZTpU$yAB;ba`f2o6DLnyx_ss8wd*%--g@}x@sp>|p1*kc>f@)+ zU%r0({^RE_kiQrim?7Q*4J(4Y#en87K?Wv9CKeWE7Iu)o7@5jJ3IthL6%E;h90S=C z3x$=88aYIqCNA7~kW<+>=!0ld(M2vX6_bamA3{I+3{xh)c6a9B`Q>Nzc%$l+v?aTit{79}| zyXs`};=8Z-pPpWMRxm8wyC6XCNl9dS>pjbfa_YZ7e{=ggJGVaNenTAF54HIsHt~;p zeR_+CKq!|+@|(+^{e{%`adkB{{^}JXJETu zfAjGCzj`13)`xCk2y_*p6=pnE@%mtu{E>R*it`WeckR1TW4u1I+)8iZ-?=MeUVe{r zJ(AC}FZAl}<0e8mWw&+w`g+^k!WgbU-2O*c_*=)1mmk8vUHiN0Kf{AQ`K|UxWb2Q| zY5XW%aQlzv58IFWN6vqnn|@>--_A)IWm)Bn4zoU;diF>=Y^Qb9(>>2_H0kVr|FquX zt#bbltDB;HqW>8Z?=ELw@t>h(xe4Q684^6r_-9`I!GncSC;v0B>i=hG&YkzzdsgN3 zZw=E^HXe&m|Kn3*dYxy-&nEjzX0Lmf|2n+>sqjBOF24I8g697)d!4sz!}0$NyllTG zE_UAkPfbqd-}i07{Xbv665GFe7e?xUq?Ucg+y8Ek(4dZd&fD^Zhn3t>)JcF?XDVaTb^}vfqSRRj7;V~Qy9OciUc~a5{<)3 z-(HHi6&q)C;xtdLqDOLO%vHQTuZW|P0EGKd7aqF~WK zcg?5%XAq3j5PKu@??}xy3-y0OdHa28w*FPR{<&6Z`ybbG#^3JpACAQ6vH#^c-v4)2 zgZ&aIjYSPy*s%7`SN|EBF8!(du>a8eTju{bBR@=z`@7-m`legy{rePOnade{wEE*P z{jinHKJklhq}~T@-ZkT_jKTThLbKWVyvM>)j5hQhdmQglcXl7k1v~SK$KT@qZm3W0 zzg7Qe-^$?7!3Y6n~UH8g>3aexDqRy!byc*GFq>ziP({M_{B^)f&I-?(LZnMuFHS$%kPY{zgGWX@qE!ek{_&tuKr1V zG}rmiKJgDcX7kiG&kvb(QDy6WDoW`MwKpzi!)7J$vQ5_hK5c zUsiKG+Oc!i;}m_9u-77<-)7IQkYRpTrTr=UoB!XPdn7-6|HoPSpMmAy-zEPUvi~!5 zn;TVJK3>Q0;fUKaTdmij*Z#P#%Q7>tpP0Hl;;`=3w^!C(+CMp$dEeFYTY?h(m;BrA z3v99Pn#X>@PNAaQ=X%bUSkE{Q-94TU=ei&MH7Td8=jS!?56;D$r-WE0YNj6MS*@uc zf7btx`1T|JR6qP@_#;yMkN3*<3pI`_B5%dl)K9wh$=dp7?xja&doKu13+UN>J$u*N zgpkz+HiqoKrmuh2{%!Hb?f)5?I_eKr>`%0Bspr;Ncy*t|zY}4*<{ydgzNe^~x@pU` z(ujq=(w@#wjsEUc-PHAB-BTv@DQ!Zx->iRGg*{dO+5BVg%9mmFA0qm1gdKYyw7olE z=MVmmV%iz0Gs8UR{|-Lrzfok)#+xGR8~+&YE(u$I<lV0aFuy*9Eo>&PZ(w;g{(+%o-ubp}du$F0t-l)U?^9zr+7C98COj+t=@2 ztl#~|=cb!{TWK^i+5Llmt6=P8%Yd^Yt0cY}TKp4^U%B;D`62lm!QYhr&fk;Fe?-5b ze&hZ_`BZagh+j*qy&=qeI`g5%F^y!y59 zKLdN9TF0)f7cNGBQ~vF^S$O}1_3F)%4G;y8G)_)E%<_5XFDv^gphN zk8eC`|7Q2G{qW5FY5y5I=V|QFnzoN`UiM2To@d3)_=k^8)!%ae z4y-#rf79~jH-CzMJN=2eWTU$%Hnz6itM6aY^<7)9U3#6l{N}N>h4mG$mZz@W5_INy zi<=4K7g^Dd>)(9;?OK!ecfp?Yby=J1PVQ6vp#SEj+?=o zHY;_HuAS|$UVV1G?$TSEm85kHOVZ!Q|E{h(vwx#ao$SuPi*4dpy^Km*EPspl+02Kw z(a}xkgiAA%CdF=@y5)X)q~80rx{vQSYo94&6ZAU4_$^oT)BHCpf2Y*2{@qez{L%Pm zJi{LMm2o#KtdCv4&$lNycg>ITfQ$JhXVZ>2T@RZaea}&(@nU+ry`Ej|&U@=te@$hm zw~JGf-?sJoAJKQezn#DSpW(q=dGXTuH@_c>XMJZU`a|6Ba!u%mm(L~#@4hsp1b_kkGOnmzpHzs7fAnJp{u)A`EsfD&RMV0 zh2vrlT-yET!%_Y(jjjx$KdXP|{5usdXyf`=Ua0Qce+HI)`Zd|jkHh9aQ2ih_{Xu_Q z&<{4(J=>;zxf5f$yJE5bG-*q<^6k|-m3D9c{P0pPV`R#F z-QGWv|1+@6`l$Za@VD8Y?2oP25A^e9-($GCM|WvW)Q9~od!iri{K~8ExP9A|8p{Til4x^4fk`9DMU>E7&Pb)uK^R6pm{Xg@w}v3P!{$Fur-(%e7nPKBvgn%y}iCfX_# zZ~n`1n#S_phqFv8X5^-(o>0DU{nP3H46L88nDQF`J=eeLYOvS;XZ^?GKSPtrztic5*8cXXvHd&CPENKU zrar0uQ2yeIc;|l?e%nv|*1!4hQsJ|o{=6uEbMC&W@%Pqh_Llmj_dnF_kH~XX$M&GwJ$$PbLAs0?crW{_h$Spf2q?fAADt4RXQ(Ty?C)}(*}hH*EK&{-Q%AB zLo5AF+T;V16n?ON)NK38!}#y^kJ7Vs&8xIlga(L|Fg4iu{%2@o{@YUj;#8eb{lgs> z_y3gZ|B+yS!~I{+@`vjGqW3xwKa~7f-#pG(J| zoYgVV^7_w^@!S6NewqIa57t!qACm9=r~8BVq5h5QkNz_pv6qO5JmPhaS@NWKN?)Pm{bLwx(8E)S=%VM3ruGob&t9~8b!>=J#ZN-_V^vUMM z_x$x~KQup1e>nfG_=oO?`;W&r*J-uK{0M#YR_^{0E4H;vHrd751x+3&-9szx^R{(f zjg^d)4V|)H_h7I9w#4~xWm&mwWgA!@ZJDjo&-%(_hA${^9x1{zuUN z+q|n^_i}&B`B4An;78_|OK+#W58nJCZ2H64yy}S9Z90>dZn9Pq`&n+rmi>A6H=d90 zkL(xzarm3;-(~+9GG)0u?Tr3J|G52;|6sY$jf(!z?vM-bN@$X>K^N5h3huK@*OG{b?dj4tZr#s z^q;|P*VW}6FVE+lHOdq>`nyb~CH~HT2JRoxhwZpNyz76+&stG-+~dQvxlA`-{z{vf zHf`Iq4GRt(7x7rt(NGd#c(gA6Px#;N{|wpuo%P%5+xBNx^WSDZR5qWhMDvaEhy6`o z^;?9ps@fX!_Umm_o4?X*(}bfdvIK08E{@;ZvOYgoe=66C>i#Wtiv!r7*X{k!z;g8O zv_GEfv*VPml>TSvS-mn#yeK|q?fkd8AJxv?u~~QSUyQ-)l_H+gEL=ieWwaU$CgAMlGpn7;>Y?U`2s(76+C3BdzBmY?NvlD_jlz~r^;iM z>leIOz%TG){%?za=k2BQx10@s?0=x1?Z^I*jhzcN?fmH8`ld88_hR3piCaEex~k9N z`b@7P;^rRTkHrtKH}6yUWAG#Lk-hMmdci%Zs*ir;ySLqo?w&p4&4S;qciwDVTxoV; zWvAS;*a>U4mra=dIdAPHe|KY-v<#N+=d0dn&U3K+&*1DJuUUVX@!ui)FRAvN_8;zK z-2c<>{>MQ6jq-m6x8M(x|1;2Dg;_KI~B8;E>vB-SE&>tTiKKGB^kEI_@Ke{$` zW%hoqI^`E}>KERWdiRR``hED<(S3_~_dea7vt!%Dhh-tN%zwrye^z|huz;VJm~8+0 zW}Qq;+>i2)Rrb>J+xMyU2kiK8y;I*t`H^%o&$jDPc}p`6c;^@LteWKJWfSanW_Q~5 zo!fVG>@hy7{9!)-e}=5}H=jRR-lzPd_yK>HnN)xGvdd4enY<9QOzIBb+~(3%z1A$< zwL4&YTV#@F+SbY-^=YPMVWlk0Q;BjMj+*9m+sFBDdjB)9T>X)szVMa3Kz*8g<1X30 zm8)<4sP~y2`N6L-WqSGdA|1196HPYsem<+MrQ$ukEI~v#zWn;*`3E8|f4ldep{cv> zg8i1djVpEkGaTr@c{yzUgY$=ZbyN7W)w^ch)2sTC=TndH)#>CfBE*Z~o7)<^J*d zA8Om*e0`j2?Q^vz{iFP&9xI<~RabYNyEaes!sF>jE`kULoB{JkiY}9`n{?Xm?p}(yr`LXx?4y$i7m*2T_GE;4J)rO@< zHXPO773~sqPb9j6$yw?clhOrt#)qKZ5$D;D{DEn5i;TZ@rd!AOpiP01r|@F!)eE&w9c)~Gn*Ub%(fEz_hwt~_m)^%vBlEYzK3(i1 z|6zIV7ync~=6>(pBbu4I+`n|SXW=(q&36wrRFq7q(2czxvbSDMedp#*g&oGbqyGl~ zw!fA6pJBuIKO+9e|1)e{*KZy9@0`4}iLCQu`$KotvOnZ*@vS@eO5#uW(ugDPqO3Fj z-CzFd;_YKBnL57~Yb~0fy%{u!@L+a%y>w0C@1*QF&L5kX|42T#e~bL#z4{N2AMKXz z=RCRMm2q^$-(C0LR^?v0cWB!6{N-8UVYioW-|1Sh=IM>oEE{4N>iU1kAFyNl5&zIv z`@nr(8{s7tF8`>5Eo7uUt?SlT>u<&IsP>$T=q?~$OJGuxu> zm*j4|7IynDv#Ug(#bcHSdTf6F&*RUf%>T6Yiv73b{|vu3&tmxd<4635%LneW{*(G+ z^TYPT>BFy=)|h=*)|&ZnK7VGRx5~=&#U+lS=b(i0}Sbnm=5zRdi)ot z1^hks>G^%~Th4ddL|1;8{B7CaDe51}``&z6er578IiZgta!McM)+w2tc%51HI=`0X z_d4Tm)u%Zsy5hCGTRZ3N@&5Mw@0>lwzn$wY)PL|hYwYwRQ}y_vc>X`(?T_q_tQU>S zDl6;H=5K#vDm|C&QpLT{9lLwK&fXn4&Eir>&u!~{XAf+D`Ba4Q=h5Gp|1Qo``Vsyy z`&;4JR%5=S%aJhkdj^YMT}o@EvQFGjxf5C8y~V1BW?qVkd}%dX zN9Xi&NB%?eyX2*E{)yL^ZMnWbGhnXmj$ip$^l?ET&U?DtrIFZ<81asO@W;$zvrHZR~mf4<{C!>6hIH*Wts!GC1` zU)w*H>n~XS`SYXyKZ9n#-`@Ri8vc0yXSjU-@T?#I4*OoQ&pLlQ`5%|*x_?*xGf0)z zGJo^?!T(L3;YavkEB1a z(~70n^@TX!tb3ckwY$4|1@}pv6RVfFYDCIDTmMS@;I@5+n?EdT%>KxIL@I6hW0!3% zSHAK}drtS>v}5*mlnZ#I>0uM@mtlD+cTe})!w|LaOS zKCLsAesuZgt|Ng;iW1qr_w8qIwRif@kmT*pp820)WB;4p)DLeW*B}02Cy^oW!s$@F z*_Ft3b8~e6EWdMm@u#NT+~dkJ7ueF@*#C~JkpA}N@ANv!x~u;gcxzPGzo=vT7#(lg zHu+I^g~HXfN0)v*+uhyqa9W7Fe$Lws9=DwtDo?CmxB8>_Ki-SGw(j}Q&}3D2GU(tq>KCez-124GtKY}xi@=PRbf|E_3?(1LUlD>7?y5G_ogn#4Zg2ZD#n7MYhHTxLyDmE>FktLgYMRnKcD|IG`YOCm$FaSzxDdt&%e$4 zGgs>hyMKJ%RciWo)gSH!8Mp52nqp>^-nlN-H`#Z4c_^E#by(vfqg9K}d|zvHROr-- zeXl<}f4KkX`_4Mm{|rrc{}}$Awa?`CAA=vAYisf@ulRgG%H?%7 zwk+230=afc-=C;b#;>gq{^38v4~z3}7XRZo`8#9l_vznMw_Uj9HaqVC+uo&fwq-EC zd;dfI`yTMgu_oSner{pKp{)|`t&ye@;p8OYYJE8iA^=s-s&1$gQvHnE- z5A_{a|8dk^+y5cx{f*Wy*|YQ8;$%OT&Hgz3;cZ`=G>$L(CEUwPYcunO8lN8K+q?Yr zI*~8pU5mL^E&j6q;nC|yv+r_c?$du^Cx3ZQ@V9Ld4?bL5TfE}djDp<}r%m_nZoj)< zd$R=hXPJ*b=RWwDGyg-Je*Z;B&Cg5zPX42*@@iAz-Wu;mfv0}Gz4=4Fis7%|hwE?N ze&9a1U#Rqb&pe?YiVtP=A3a-fop)u$V*d|M=k8luc0E4*x97B%%0fG5znL~K?b*+N zC;8s|^xXbD{6E8#1=004S?mAWF0FkX&uaf?DbwwLC$#@FynL&{{5}dgD`KbecY}S7 zcKyv+^^NoSYNQ_oKGwe#{%C$@^r3jZJ)(a%%T3#U*_HY3y?e2Drc8bN<+pXjyzK6l zrgYaED@FRXG(Yt7{AW1m_LZOi-_?6Me_QL!{wR6aXK^gPymdb3%X|FSA6&`Z?lKQH;>+&1>_J92RIQ~uLZ{HfdA4`}2 zh9xvofezdNx;NoZfvEFs_5C80CcRf>6ezl(6H}~P~ou+QN zM(46u@2>9dSg*2gQs$b){~0{nbUQiNug7mPf9sq2JNA#&wSO8J_t|ZdAG{Sif23-D zYwPx&zKP#vzWcKKb+35<$2RfrSz^++y;s-lR{P9Z!Y{47#ZKk#s<$@UzoY)>{hgS< zkF(;OZ}~APwv~@^)sJ2{xoBJCH(#Ad-OnfIy2P#Q%k}o(e*2r#x$jxwC7C)afBych z`078y_V7dbP50P;m}mdy{IUP=KE3O9Ru%0>qrUBaJ z9zDw5c4@uuE)|0v(bJ!PQ~UNUzx|%<-&J<{|L(*y)>+kL{+$zjV3&D=4ddhg44hfw z*^hdy!!B>-ERC&qiB((^Cs}vt_m}(pe>WxDZr#!S_QDbK6Pr~Wr1x)HHgCS5ect>Z zn(4>oMLfUF7p@3D8l`?vpQlr)KX2~hsET@zk31`dbMMGK4)`c~`Am7u%j~o@_7|`1 zS^O>ehw}sbmiQ0h?|*10{ZP8}&$7n(L-v6<)oW^3wx0eQRry}^YE7!}roDGA?a6$4 z`#?9B(Xno+7T5JYKb%+ZfAjP|11s0xmHPyL{Cjlo{GtC0a{6!VwEmc0SytP*;?=e& z-D$n+UcB(Xx2x&8%jK;i{`*bDxBE(oY}k=f-%y{Tf9w09`P=)C=-(EO{kz77x%R<( z(TaM%4{_@sbo)1#Uz_xwA?4-tsJZv%KY6A9NYX2Aan^Qi)q{--r+OUSk{X`DeluRy zKI8q(-{0atOq>1q{VnUq;jMo-A5@?9EUAu-Kf3Gbw#n(Hw~ynyUDrbewg^kJ*dA{b$(T^;dpT1J}RWf4qOPekA_3sXtg> zpOt?z`*57z_UVp4K7M%Z_oLNxQrv%r#hLp|FDCxBTe$qNko!~Jr{~)BX0ABX^RK`o zY3lXVBR==H*vs$H{8)W_K3kn~h4BOZqqpN3{={D`Ill42pY+OyORrycoB3hc)10`9 zph`jWDSW?~-=uqnMydZ`KT`j}%fCI!{m}Uv`w!0F{Qk(<=tJ`b{&Cj?Zu_w?_3_#$ z*6Ul>3*Ghp*0IOIbaq?C(w&pT+TOj1IkT?)%tT4I6W6pDUhA72{;>QX*Zl{t`?=5P zezEWQ&%j(d`@L9%dtSH9t?4aaZG~j*er$MtHrrn~_O{3K!jdhU;&(G$KeB(*v5g;& zKVJTJF>Gz9Q-@^Kf{BK z^&k9apR~`s`eWvQ23E-*Nv!*izRkOS_;K8i&SddF-T~1w>P|oR+WodJ{l>?4-S2a4 zOzU2SpSItufAGF|jr{a)o%y0?liogB-zBxar{w%bzfW&B?-F}0Fuh3cW_`)+DS6EO zGcK@Sx%%Vee+Cxzk8JB7&;Ox%{9t{ToW?B6J-LtmGl=~-e{|O0D}j|skG_3B8g=Hg zow?!fvyIb|w}#L9JA3^x`5%g+(j|j&F($B zf23;a9ga7vR^5K1pOeP7idpB?;r9XTFZ%obGi33%$n*ROtbXubJiel}^mc04jLd)R z*G)MLUdfi7&&^cv{WSIWy21;eqvCn(GxoRc7u))KJ#U59=h)gP>EN2zD}UHWTw3($ zu#${-X||AYUg=Nfyx+$q!jA7gspQu4$sk15(_)!xAC>q8;eQKdTVrpGs9=roy=4}+dI+S`1#XY_qW?K z*xCM(`@3=L_5U;Y*YjoH{Zs#2_1~%cVs^?I^Tq#Z)Sdaq@KOHg zT7%oN)<>njH*b0C9Jb}R%39m?Q%iMpwJMEvpOm}y_x5I^2b1FjKg$0LTKHSK{wCv( z>His)?{7E##qJR!h_w!hi`yWq#~qf+;KzvkcG?Q&s{Z}!9F zhyNKk);HCO*!E8CJ+f=s%-ZtOTHbf-tG~TBH94|{qc<<9>D}w(pM9H_zcdwL{8awt z_t`jDN_kN)5K71e?NPX4G*e&lOuTCuLi zP~>FklFVOor{3|G_FtCUb;`2b_qprxs5=`ymrl~y@1n7QfBrs>f2ZbedjIC!Kh5di z3jWUC!}{S@Y{|jD+wO6EsGGZRuJfCJ`8WSv{1!3!+^0V;x8vbYclj*oLT#0xyM|{-jB^k_9^WD`22{y z;NiT){*ddYlD$W7AL@y`bV=rTX14I=Jz>+zHj3A47yi1`#h^XqV}0wEdYOvwBl|c% zs&4jw_%`WKu6{tPO2#Y?wcbS&omcYg49jyoakjK1fL;B;ea?(J#t-vb|8PF6R@?qz zU+=PmOJ06^Z+t4biAB(5>78jgN*Z_0c)pJ}{?BmGp+4>R{#*YUzA61(y+6&?=#fV0 zd+8tC!5{ujwmm$xN&98){Wp_5`^t2WPdWQ$*}fx-8tkn9HvVVG)c=wF{>JHV*?$+m zTht~mTrvO9wC#4vmmhixmb^_e{cX28<vQWxukO|iaCSJf&*aDN{|u}%et3Tf zs_&S!z12Q-e$RZtI?*4&$F}X~{rX=1hrG*0_x6PA@ABQ|n0%QZa8*}j=HopTYnSfm zQs35<8KyonzG(fm`K)QIy+TVQr&%kp0?@Alv-{y5^_kZxa-y>en zm-C+?>3&*HU=sr_jFJA3VahTNAI;$BX-$_e`wuyc>V-TPK?_pP@W z9TvM-_^qSCKEF=n$K@mQ1?%L0)E~3c{^9vZp6N%|7w>QLxhs~{8s!EZPgyVZ^ZfFA zvA4E;b)8zXyZxtX>}~lX{b$qPF#p~Das9W;{~4O**WGfCsNUc5YkQZ;{HFQ*HMiAT zJkuXatb24dPqFylHu3AFwn?IepSItK=xJJ0@324PJ@cQqA9FusAFJoLW3LHmKPWF? zx+2)uUwq%J>({M(_w=nUwp|i^p>|_}Q6=A#<1)8pFNHb_zxc!aL-@n?Z;3y2KOFy7 z^F#e%#g_QiI)RG|FKp2@6VrWqQ0Oh|oj;d6p6h+u7w2AHraEI5!?&s*n*SM|YKYzc z<{1BiR+d{|uTA+x|0b;`-0c{n@N_NfRkETV4VNRy0Tla)5oWwCzV7G@8@9Jr3Y4$;$>UXZ*f*Q47-L#kcSp3HP zw_hLGcmHy0T$?SwY5rUB6`4`--ANa}?Cy2lqx?9#Lh16FQp@D_V%KG_!U`jA`rA)C znO~fosk3fkjIT=knvwwa&-;IuX8mW_B;O5MbW^AH;rky^@#9rG_M4U;zTdJdyt7X9 zkI~20FGU&qjIV#yUYm74bZ@)6{GRJuwXLhQrM;_F`yM{b4Xz3Jc|Blnb^afL&EFJ1 z%ztD3pMmB3kMQD0{5Kza{HXu9|H!oReM%o2VhxqAx6b)BZ|RE6u&Axar%d)OOiip6 z-L13J&?c|>-SxN4N*j4jaq~_2#qej<-<}%L$Nl~CTh$u9og`Du@o$QsIsY?c{}W2ue`^1tUjN|BUt-Mzua)MyNyn;P6W_IS*Up(qT@n}a z%FFYZ8kS76)&6^3T*T0y_qWS))rr?AT-5(# z|6%sSZH*6W*}ezPj@+~H!@K_cWw*~)7X5ywm(nK^nz^)o<`ad@^CBj@iZK4*{LjGp z;^Xn&I?0Od->g0!KU^=7HBav2icKHwrkVEg2h2M5BkHtTr^<%Pi$?pWywA;hGxOG2 zmXxNz!r!sKm9neOciN}w->g1jr*!q*`mcYTAO7pEtgo#u_-w)p;p-yZQUUjK3m$R_j1$gUL1{adLmHZek%Ltl>ZD(Vl}Qmnm;CgYx?p0 z(fqDD>uWXMkE;DSoR>$vic`3%ekE_=_TP#1s;V<*PP6^bV0NHzUg0c_1^h36A!Q}x zY=w)>7kzY|$cOFydo)1>(Cfodbz2|I&Gw(|d99>2>YVjy>EDr8j+%%Icu1;tdEA`1 zxFB?DheDI9@56lVAK3@(WIz08X!;}h@V2b-!CSsPRe95wyeyk|>*medN4h3D^B6Wv dJl3%=RD?Bvfq~Iggz@4<=(G~rs(Qx%HvtqCjn4o8 diff --git a/doc/src/Eqs/pair_lj_soft.tex b/doc/src/Eqs/pair_lj_soft.tex deleted file mode 100644 index e32f11f0aa..0000000000 --- a/doc/src/Eqs/pair_lj_soft.tex +++ /dev/null @@ -1,15 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -\[ -E = \lambda^n 4 \epsilon -\left\{ - \frac{1}{ \left[ \alpha_{\mathrm{LJ}} (1-\lambda)^2 + - \left( \displaystyle\frac{r}{\sigma} \right)^6 \right]^2 } - - \frac{1}{ \alpha_{\mathrm{LJ}} (1-\lambda)^2 + - \left( \displaystyle\frac{r}{\sigma} \right)^6 } -\right\} \qquad r < r_c - \] - -\end{document} diff --git a/doc/src/Eqs/pair_morse_soft.jpg b/doc/src/Eqs/pair_morse_soft.jpg deleted file mode 100644 index 9c8321eba798943de9ad293f80e95d946e872f95..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20988 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 TmSyXa@`{yCpivd-;Qu!P`n?t+ diff --git a/doc/src/Eqs/pair_nm.tex b/doc/src/Eqs/pair_nm.tex deleted file mode 100644 index 4adf9331cc..0000000000 --- a/doc/src/Eqs/pair_nm.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ - E = \frac{E_0}{(n-m)} \left[ m \left(\frac{r_0}{r}\right)^n - - n \left(\frac{r_0}{r}\right)^m \right] \qquad r < r_c -$$ - -\end{document} diff --git a/doc/src/Eqs/pair_srp1.jpg b/doc/src/Eqs/pair_srp1.jpg deleted file mode 100644 index bbbdc43e059778ea54c2d297deade4cd99f735f5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3537 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 S`Q_=^cix>8q!tkWe-i*dtf3_U diff --git a/doc/src/Eqs/pair_srp1.tex b/doc/src/Eqs/pair_srp1.tex deleted file mode 100644 index 45aa005d86..0000000000 --- a/doc/src/Eqs/pair_srp1.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - F^{SRP}_{ij} & = & C(1-r/r_c)\hat{r}_{ij} \qquad r < r_c \\ -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_srp2.jpg b/doc/src/Eqs/pair_srp2.jpg deleted file mode 100644 index c5d20dc212782398d5130d026444315148d1866b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5648 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 diff --git a/doc/src/Eqs/pair_srp2.tex b/doc/src/Eqs/pair_srp2.tex deleted file mode 100644 index 19cb19ae72..0000000000 --- a/doc/src/Eqs/pair_srp2.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - F_{i1}^{SRP} & = & F^{SRP}_{ij}(L) \\ - F_{i2}^{SRP} & = & F^{SRP}_{ij}(1-L) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_sw.jpg b/doc/src/Eqs/pair_sw.jpg deleted file mode 100644 index f60f07fd27d233eb6e5446aad7c3c42fd6f1bfb5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28707 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 H|8D{S{YM^) diff --git a/doc/src/Eqs/pair_sw.tex b/doc/src/Eqs/pair_sw.tex deleted file mode 100644 index ebcc39d77b..0000000000 --- a/doc/src/Eqs/pair_sw.tex +++ /dev/null @@ -1,18 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - E & = & \sum_i \sum_{j > i} \phi_2 (r_{ij}) + - \sum_i \sum_{j \neq i} \sum_{k > j} - \phi_3 (r_{ij}, r_{ik}, \theta_{ijk}) \\ - \phi_2(r_{ij}) & = & A_{ij} \epsilon_{ij} \left[ B_{ij} (\frac{\sigma_{ij}}{r_{ij}})^{p_{ij}} - - (\frac{\sigma_{ij}}{r_{ij}})^{q_{ij}} \right] - \exp \left( \frac{\sigma_{ij}}{r_{ij} - a_{ij} \sigma_{ij}} \right) \\ - \phi_3(r_{ij},r_{ik},\theta_{ijk}) & = & \lambda_{ijk} \epsilon_{ijk} \left[ \cos \theta_{ijk} - - \cos \theta_{0ijk} \right]^2 - \exp \left( \frac{\gamma_{ij} \sigma_{ij}}{r_{ij} - a_{ij} \sigma_{ij}} \right) - \exp \left( \frac{\gamma_{ik} \sigma_{ik}}{r_{ik} - a_{ik} \sigma_{ik}} \right) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_tersoff.jpg b/doc/src/Eqs/pair_tersoff.jpg deleted file mode 100644 index bd3e147192707ee8845611fb31abb71410e67006..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36139 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 C!yV@U diff --git a/doc/src/Eqs/pair_tersoff_1.jpg b/doc/src/Eqs/pair_tersoff_1.jpg deleted file mode 100644 index 79600b499c33addbdf11e16602f2867fb02f2b4f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36584 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 R + D - \end{array} \right. \\ - f_R(r) & = & A \exp (-\lambda_1 r) \\ - f_A(r) & = & -B \exp (-\lambda_2 r) \\ - b_{ij} & = & \left( 1 + \beta^n {\zeta_{ij}}^n \right)^{-\frac{1}{2n}} \\ - \zeta_{ij} & = & \sum_{k \neq i,j} f_C(r_{ik}) g(\theta_{ijk}) - \exp \left[ {\lambda_3}^m (r_{ij} - r_{ik})^m \right] \\ - g(\theta) & = & \gamma_{ijk} \left( 1 + \frac{c^2}{d^2} - - \frac{c^2}{\left[ d^2 + - (\cos \theta - \cos \theta_0)^2\right]} \right) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_tersoff_2.jpg b/doc/src/Eqs/pair_tersoff_2.jpg deleted file mode 100644 index 6cb8778a094253cc38776e110baef3e89948b75b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 13756 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

    OT~H=0i{em;LIfvJ%t#RX49s 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 diff --git a/doc/src/Eqs/pair_tersoff_2.tex b/doc/src/Eqs/pair_tersoff_2.tex deleted file mode 100644 index 7b5beb8ef3..0000000000 --- a/doc/src/Eqs/pair_tersoff_2.tex +++ /dev/null @@ -1,14 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} -\lambda_1^{i,j} &=& \frac{1}{2}(\lambda_1^i + \lambda_1^j)\\ -\lambda_2^{i,j} &=& \frac{1}{2}(\lambda_2^i + \lambda_2^j)\\ -A_{i,j} &=& (A_{i}A_{j})^{1/2}\\ -B_{i,j} &=& \chi_{ij}(B_{i}B_{j})^{1/2}\\ -R_{i,j} &=& (R_{i}R_{j})^{1/2}\\ -S_{i,j} &=& (S_{i}S_{j})^{1/2}\\ -\end{eqnarray*} - -\end{document} \ No newline at end of file diff --git a/doc/src/Eqs/pair_tersoff_mod.jpg b/doc/src/Eqs/pair_tersoff_mod.jpg deleted file mode 100644 index 2618943d85d79e82873253fea293fb98c4d5ac21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 91727 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 diff --git a/doc/src/Eqs/pair_tersoff_mod.tex b/doc/src/Eqs/pair_tersoff_mod.tex deleted file mode 100644 index eafc4fdeeb..0000000000 --- a/doc/src/Eqs/pair_tersoff_mod.tex +++ /dev/null @@ -1,24 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - E & = & \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\ - V_{ij} & = & f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) \right] \\ - f_C(r) & = & \left\{ \begin{array} {r@{\quad:\quad}l} - 1 & r < R - D \\ - \frac{1}{2} - \frac{9}{16} \sin \left( \frac{\pi}{2} \frac{r-R}{D} \right) - \frac{1}{16} \sin \left( \frac{3\pi}{2} \frac{r-R}{D} \right) & - R-D < r < R + D \\ - 0 & r > R + D - \end{array} \right. \\ - f_R(r) & = & A \exp (-\lambda_1 r) \\ - f_A(r) & = & -B \exp (-\lambda_2 r) \\ - b_{ij} & = & \left( 1 + {\zeta_{ij}}^\eta \right)^{-\frac{1}{2n}} \\ - \zeta_{ij} & = & \sum_{k \neq i,j} f_C(r_{ik}) g(\theta_{ijk}) - \exp \left[ \alpha (r_{ij} - r_{ik})^\beta \right] \\ - g(\theta) & = & c_1 + g_o(\theta) g_a(\theta) \\ - g_o(\theta) & = & \frac{c_2 (h - \cos \theta)^2}{c_3 + (h - \cos \theta)^2} \\ - g_a(\theta) & = & 1 + c_4 \exp \left[ -c_5 (h - \cos \theta)^2 \right] \\ -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_tersoff_mod_c.jpg b/doc/src/Eqs/pair_tersoff_mod_c.jpg deleted file mode 100644 index 311ccc81ebaa809dea7da497439a7c79a405acd3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4211 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 QJD1fz097gs_5W`I03NQqJ^%m! diff --git a/doc/src/Eqs/pair_tersoff_mod_c.tex b/doc/src/Eqs/pair_tersoff_mod_c.tex deleted file mode 100644 index 8cea2d382c..0000000000 --- a/doc/src/Eqs/pair_tersoff_mod_c.tex +++ /dev/null @@ -1,10 +0,0 @@ -\documentclass[12pt]{article} -\pagestyle{empty} - -\begin{document} - -\begin{eqnarray*} - V_{ij} & = & f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) + c_0 \right] -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_tersoff_zbl.jpg b/doc/src/Eqs/pair_tersoff_zbl.jpg deleted file mode 100644 index 20d60d225689e11d7f347cfec1106a6e2356da05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 392677 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

    #oG1d9n}W#6@*nBg0n9 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 z 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ⅈ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 b^JTQ3ksGyPG>REUgJ3iWXtXGR`TtD-mPd6^ diff --git a/doc/src/Eqs/pair_tersoff_zbl.tex b/doc/src/Eqs/pair_tersoff_zbl.tex deleted file mode 100644 index 902819aa1b..0000000000 --- a/doc/src/Eqs/pair_tersoff_zbl.tex +++ /dev/null @@ -1,33 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - E & = & \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\ - V_{ij} & = & (1 - f_F(r_{ij})) V^{ZBL}_{ij} + f_F(r_{ij}) V^{Tersoff}_{ij} \\ -f_F(r_{ij}) & = & \frac{1}{1 + e^{-A_F(r_{ij} - r_C)}}\\ - \\ - \\ - V^{ZBL}_{ij} & = & \frac{1}{4\pi\epsilon_0} \frac{Z_1 Z_2 \,e^2}{r_{ij}} \phi(r_{ij}/a) \\ - a & = & \frac{0.8854\,a_0}{Z_{1}^{0.23} + Z_{2}^{0.23}}\\ - \phi(x) & = & 0.1818e^{-3.2x} + 0.5099e^{-0.9423x} + 0.2802e^{-0.4029x} + 0.02817e^{-0.2016x}\\ - \\ - \\ - V^{Tersoff}_{ij} & = & f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) \right] \\ - f_C(r) & = & \left\{ \begin{array} {r@{\quad:\quad}l} - 1 & r < R - D \\ - \frac{1}{2} - \frac{1}{2} \sin \left( \frac{\pi}{2} \frac{r-R}{D} \right) & - R-D < r < R + D \\ - 0 & r > R + D - \end{array} \right. \\ - f_R(r) & = & A \exp (-\lambda_1 r) \\ - f_A(r) & = & -B \exp (-\lambda_2 r) \\ - b_{ij} & = & \left( 1 + \beta^n {\zeta_{ij}}^n \right)^{-\frac{1}{2n}} \\ - \zeta_{ij} & = & \sum_{k \neq i,j} f_C(r_{ik}) g(\theta_{ijk}) - \exp \left[ {\lambda_3}^m (r_{ij} - r_{ik})^m \right] \\ - g(\theta) & = & \gamma_{ijk} \left( 1 + \frac{c^2}{d^2} - - \frac{c^2}{\left[ d^2 + - (\cos \theta - \cos \theta_0)^2\right]} \right) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_ufm.jpg b/doc/src/Eqs/pair_ufm.jpg deleted file mode 100644 index 40273da68063274cd6d6496d38f93ff97121df91..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17830 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 diff --git a/doc/src/Eqs/pair_vashishta.tex b/doc/src/Eqs/pair_vashishta.tex deleted file mode 100644 index b65056a254..0000000000 --- a/doc/src/Eqs/pair_vashishta.tex +++ /dev/null @@ -1,22 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - U & = & \sum_i^N \sum_{j > i}^N U_{ij}^{(2)} (r_{ij}) + - \sum_i^N \sum_{j \neq i}^N \sum_{k > j, k \neq i}^N - U_{ijk}^{(3)} (r_{ij}, r_{ik}, \theta_{ijk}) - \\ - U_{ij}^{(2)} (r) & = & \frac{H_{ij}}{r^{\eta_{ij}}} - + \frac{Z_i Z_j}{r}\exp(-r/\lambda_{1,ij}) - - \frac{D_{ij}}{r^4}\exp(-r/\lambda_{4,ij}) - - \frac{W_{ij}}{r^6}, r < r_{c,{ij}} - \\ - U_{ijk}^{(3)}(r_{ij},r_{ik},\theta_{ijk}) & = & B_{ijk} - \frac{\left[ \cos \theta_{ijk} - \cos \theta_{0ijk} \right]^2} - {1+C_{ijk}\left[ \cos \theta_{ijk} - \cos \theta_{0ijk} \right]^2} \times \\ -& & \exp \left( \frac{\gamma_{ij}}{r_{ij} - r_{0,ij}} \right) - \exp \left( \frac{\gamma_{ik}}{r_{ik} - r_{0,ik}} \right), r_{ij} < r_{0,ij}, r_{ik} < r_{0,ik} -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pair_yukawa.jpg b/doc/src/Eqs/pair_yukawa.jpg deleted file mode 100644 index 103edc604321d02e39545dd4e55acac3884edc8c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2189 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 diff --git a/doc/src/Eqs/pair_yukawa_colloid.tex b/doc/src/Eqs/pair_yukawa_colloid.tex deleted file mode 100644 index dbdbbcd140..0000000000 --- a/doc/src/Eqs/pair_yukawa_colloid.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -$$ - E = \frac{A}{\kappa} e^{- \kappa (r - (r_i + r_j))} \qquad r < r_c -$$ - -\end{document} diff --git a/doc/src/Eqs/pair_zbl.jpg b/doc/src/Eqs/pair_zbl.jpg deleted file mode 100644 index 88656af5eb4f6ef617e1bc400e6f4eb894da4695..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32209 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%0AptX1Wi#{xwICBD93Xi#lEvKx* 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


    Z0*0{WUKD;k^QKz@0Pb! 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 diff --git a/doc/src/Eqs/pair_zbl.tex b/doc/src/Eqs/pair_zbl.tex deleted file mode 100644 index 3d68dbed23..0000000000 --- a/doc/src/Eqs/pair_zbl.tex +++ /dev/null @@ -1,11 +0,0 @@ -\documentclass[12pt]{article} - -\begin{document} - -\begin{eqnarray*} - E^{ZBL}_{ij} & = & \frac{1}{4\pi\epsilon_0} \frac{Z_i Z_j \,e^2}{r_{ij}} \phi(r_{ij}/a)+ S(r_{ij})\\ - a & = & \frac{0.46850}{Z_{i}^{0.23} + Z_{j}^{0.23}}\\ - \phi(x) & = & 0.18175e^{-3.19980x} + 0.50986e^{-0.94229x} + 0.28022e^{-0.40290x} + 0.02817e^{-0.20162x}\\ - \end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/pressure.jpg b/doc/src/Eqs/pressure.jpg deleted file mode 100644 index 525d8a75ee0747ad5b552a6020eddad600656ab2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4333 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 PL1m%)o4V` | :ref:`Pre-built OpenSuse Linux executables ` | :ref:`Gentoo Linux executable ` -| :ref:`Arch Linux build-script ` -| +| :ref:`Arch Linux build-script ` +| ---------- @@ -132,11 +132,21 @@ mirrors. The "module load" command is needed once per (shell) session or shell terminal instance, unless it is automatically loaded from the shell profile. +The LAMMPS binary is built with the :ref:`KIM package ` which +results in the above command also installing the `kim-api` binaries when LAMMPS +is installed. In order to use potentials from `openkim.org `_, you +can install the `openkim-models` package + +.. parsed-literal:: + + dnf install openkim-models + Please use "lmp -help" to see which compilation options, packages, and styles are included in the binary. Thanks to Christoph Junghans (LANL) for making LAMMPS available in Fedora. +.. _openkim: https://openkim.org ---------- @@ -146,7 +156,7 @@ Thanks to Christoph Junghans (LANL) for making LAMMPS available in Fedora. Pre-built EPEL Linux executable ------------------------------------------ -Pre-built LAMMPS packages for stable releases are available +Pre-built LAMMPS (and KIM) packages for stable releases are available in the `Extra Packages for Enterprise Linux (EPEL) repository `_ for use with Red Hat Enterprise Linux (RHEL) or CentOS version 7.x and compatible Linux distributions. Names of packages, executable, @@ -187,6 +197,15 @@ is *lmp*\ . Thus to run an input in parallel on 2 CPUs you would do: Please use "lmp -help" to see which compilation options, packages, and styles are included in the binary. +The LAMMPS binary is built with the :ref:`KIM package ` which +results in the above command also installing the `kim-api` binaries when LAMMPS +is installed. In order to use potentials from `openkim.org `_, you +can install the `openkim-models` package + +.. parsed-literal:: + + zypper install openkim-models + Thanks to Christoph Junghans (LANL) for making LAMMPS available in OpenSuse. diff --git a/doc/src/Eqs/fix_integration_spin_stdecomposition.jpg b/doc/src/JPG/fix_integration_spin_stdecomposition.jpg similarity index 100% rename from doc/src/Eqs/fix_integration_spin_stdecomposition.jpg rename to doc/src/JPG/fix_integration_spin_stdecomposition.jpg diff --git a/doc/src/compute_centro_atom.rst b/doc/src/compute_centro_atom.rst index f00cc179f8..6e706d9f97 100644 --- a/doc/src/compute_centro_atom.rst +++ b/doc/src/compute_centro_atom.rst @@ -52,20 +52,23 @@ in the specified compute group. This parameter is computed using the following formula from :ref:`(Kelchner) ` -.. image:: Eqs/centro_symmetry.jpg - :align: center - -where the *N* nearest neighbors of each atom are identified and Ri and -Ri+N/2 are vectors from the central atom to a particular pair of -nearest neighbors. There are N\*(N-1)/2 possible neighbor pairs that -can contribute to this formula. The quantity in the sum is computed -for each, and the N/2 smallest are used. This will typically be for -pairs of atoms in symmetrically opposite positions with respect to the -central atom; hence the i+N/2 notation. - -*N* is an input parameter, which should be set to correspond to the -number of nearest neighbors in the underlying lattice of atoms. If -the keyword *fcc* or *bcc* is used, *N* is set to 12 and 8 +.. math:: + + CS = \sum_{i = 1}^{N/2} | \vec{R}_i + \vec{R}_{i+N/2} |^2 + + +where the :math:`N` nearest neighbors of each atom are identified and +:math:`\vec{R}_i` and :math:`\vec{R}_{i+N/2}` are vectors from the +central atom to a particular pair of nearest neighbors. There are +:math:`N (N-1)/2` possible neighbor pairs that can contribute to this +formula. The quantity in the sum is computed for each, and the +:math:`N/2` smallest are used. This will typically be for pairs of +atoms in symmetrically opposite positions with respect to the central +atom; hence the :math:`i+N/2` notation. + +:math:`N` is an input parameter, which should be set to correspond to +the number of nearest neighbors in the underlying lattice of atoms. +If the keyword *fcc* or *bcc* is used, *N* is set to 12 and 8 respectively. More generally, *N* can be set to a positive, even integer. @@ -74,9 +77,9 @@ lattice, the centro-symmetry parameter will be 0. It will be near 0 for small thermal perturbations of a perfect lattice. If a point defect exists, the symmetry is broken, and the parameter will be a larger positive value. An atom at a surface will have a large -positive parameter. If the atom does not have *N* neighbors (within -the potential cutoff), then its centro-symmetry parameter is set to -0.0. +positive parameter. If the atom does not have :math:`N` neighbors +(within the potential cutoff), then its centro-symmetry parameter is +set to 0.0. If the keyword *axes* has the setting *yes*\ , then this compute also estimates three symmetry axes for each atom's local neighborhood. The @@ -95,7 +98,7 @@ of any atom. Only atoms within the cutoff of the pairwise neighbor list are considered as possible neighbors. Atoms not in the compute group are -included in the *N* neighbors used in this calculation. +included in the :math:`N` neighbors used in this calculation. The neighbor list needed to compute this quantity is constructed each time the calculation is performed (e.g. each time a snapshot of atoms diff --git a/doc/src/compute_cna_atom.rst b/doc/src/compute_cna_atom.rst index 16ce67d7af..f270891d82 100644 --- a/doc/src/compute_cna_atom.rst +++ b/doc/src/compute_cna_atom.rst @@ -51,8 +51,12 @@ E.g. 12 nearest neighbor for perfect FCC and HCP crystals, 14 nearest neighbors for perfect BCC crystals. These formulas can be used to obtain a good cutoff distance: -.. image:: Eqs/cna_cutoff1.jpg - :align: center +.. math:: + + r_{c}^{fcc} = & \frac{1}{2} \left(\frac{\sqrt{2}}{2} + 1\right) \mathrm{a} \simeq 0.8536 \:\mathrm{a} \\ + r_{c}^{bcc} = & \frac{1}{2}(\sqrt{2} + 1) \mathrm{a} \simeq 1.207 \:\mathrm{a} \\ + r_{c}^{hcp} = & \frac{1}{2}\left(1+\sqrt{\frac{4+2x^{2}}{3}}\right) \mathrm{a} + where a is the lattice constant for the crystal structure concerned and in the HCP case, x = (c/a) / 1.633, where 1.633 is the ideal c/a @@ -62,10 +66,13 @@ Also note that since the CNA calculation in LAMMPS uses the neighbors of an owned atom to find the nearest neighbors of a ghost atom, the following relation should also be satisfied: -.. image:: Eqs/cna_cutoff2.jpg - :align: center +.. math:: + + r_c + r_s > 2*{\rm cutoff} + -where Rc is the cutoff distance of the potential, Rs is the skin +where :math:`r_c` is the cutoff distance of the potential, :math:`r_s` +is the skin distance as specified by the :doc:`neighbor ` command, and cutoff is the argument used with the compute cna/atom command. LAMMPS will issue a warning if this is not the case. diff --git a/doc/src/compute_cnp_atom.rst b/doc/src/compute_cnp_atom.rst index 3290f67508..42e187ba69 100644 --- a/doc/src/compute_cnp_atom.rst +++ b/doc/src/compute_cnp_atom.rst @@ -40,13 +40,16 @@ only be performed on single component systems. This parameter is computed using the following formula from :ref:`(Tsuzuki) ` -.. image:: Eqs/cnp_eq.jpg - :align: center +.. math:: -where the index *j* goes over the *n*\ i nearest neighbors of atom -*i*\ , and the index *k* goes over the *n*\ ij common nearest neighbors -between atom *i* and atom *j*\ . Rik and Rjk are the vectors connecting atom -*k* to atoms *i* and *j*\ . The quantity in the double sum is computed + Q_{i} = \frac{1}{n_i}\sum_{j = 1}^{n_i} | \sum_{k = 1}^{n_{ij}} \vec{R}_{ik} + \vec{R}_{jk} |^2 + + +where the index *j* goes over the :math:`n_i` nearest neighbors of atom +*i*\ , and the index *k* goes over the :math:`n_{ij}` common nearest neighbors +between atom *i* and atom *j*\ . :math:`\vec{R}_{ik}` and +:math:`\vec{R}_{jk}` are the vectors connecting atom *k* to atoms *i* +and *j*\ . The quantity in the double sum is computed for each atom. The CNP calculation is sensitive to the specified cutoff value. @@ -56,8 +59,12 @@ E.g. 12 nearest neighbor for perfect FCC and HCP crystals, 14 nearest neighbors for perfect BCC crystals. These formulas can be used to obtain a good cutoff distance: -.. image:: Eqs/cnp_cutoff.jpg - :align: center +.. math:: + + r_{c}^{fcc} = & \frac{1}{2} \left(\frac{\sqrt{2}}{2} + 1\right) \mathrm{a} \simeq 0.8536 \:\mathrm{a} \\ + r_{c}^{bcc} = & \frac{1}{2}(\sqrt{2} + 1) \mathrm{a} \simeq 1.207 \:\mathrm{a} \\ + r_{c}^{hcp} = & \frac{1}{2}\left(1+\sqrt{\frac{4+2x^{2}}{3}}\right) \mathrm{a} + where a is the lattice constant for the crystal structure concerned and in the HCP case, x = (c/a) / 1.633, where 1.633 is the ideal c/a @@ -67,10 +74,13 @@ Also note that since the CNP calculation in LAMMPS uses the neighbors of an owned atom to find the nearest neighbors of a ghost atom, the following relation should also be satisfied: -.. image:: Eqs/cnp_cutoff2.jpg - :align: center +.. math:: + + r_c + r_s > 2*{\rm cutoff} + -where Rc is the cutoff distance of the potential, Rs is the skin +where :math:`r_c` is the cutoff distance of the potential, :math:`r_s` is +the skin distance as specified by the :doc:`neighbor ` command, and cutoff is the argument used with the compute cnp/atom command. LAMMPS will issue a warning if this is not the case. diff --git a/doc/src/compute_dpd.rst b/doc/src/compute_dpd.rst index bca72efdcd..cb3008a73c 100644 --- a/doc/src/compute_dpd.rst +++ b/doc/src/compute_dpd.rst @@ -26,19 +26,26 @@ Description """"""""""" Define a computation that accumulates the total internal conductive -energy (U\_cond), the total internal mechanical energy (U\_mech), the -total chemical energy (U\_chem) and the *harmonic* average of the internal -temperature (dpdTheta) for the entire system of particles. See the +energy (:math:`U^{cond}`), the total internal mechanical energy +(:math:`U^{mech}`), the total chemical energy (:math:`U^{chem}`) +and the *harmonic* average of the internal temperature (:math:`\theta_{avg}`) +for the entire system of particles. See the :doc:`compute dpd/atom ` command if you want per-particle internal energies and internal temperatures. The system internal properties are computed according to the following relations: -.. image:: Eqs/compute_dpd.jpg - :align: center +.. math:: -where N is the number of particles in the system + U^{cond} = & \displaystyle\sum_{i=1}^{N} u_{i}^{cond} \\ + U^{mech} = & \displaystyle\sum_{i=1}^{N} u_{i}^{mech} \\ + U^{chem} = & \displaystyle\sum_{i=1}^{N} u_{i}^{chem} \\ + U = & \displaystyle\sum_{i=1}^{N} (u_{i}^{cond} + u_{i}^{mech} + u_{i}^{chem}) \\ + \theta_{avg} = & (\frac{1}{N}\displaystyle\sum_{i=1}^{N} \frac{1}{\theta_{i}})^{-1} \\ + + +where :math:`N` is the number of particles in the system ---------- @@ -46,8 +53,9 @@ where N is the number of particles in the system **Output info:** -This compute calculates a global vector of length 5 (U\_cond, U\_mech, -U\_chem, dpdTheta, N\_particles), which can be accessed by indices 1-5. +This compute calculates a global vector of length 5 (:math:`U^{cond}`, +:math:`U^{mech}`, :math:`U^{chem}`, :math:`\theta_{avg}`, :math:`N`), +which can be accessed by indices 1-5. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. diff --git a/doc/src/compute_dpd_atom.rst b/doc/src/compute_dpd_atom.rst index 12956cc5d6..215e16a9c9 100644 --- a/doc/src/compute_dpd_atom.rst +++ b/doc/src/compute_dpd_atom.rst @@ -23,10 +23,10 @@ Description """"""""""" Define a computation that accesses the per-particle internal -conductive energy (u\_cond), internal mechanical energy (u\_mech), -internal chemical energy (u\_chem) and -internal temperatures (dpdTheta) for each particle in a group. See -the :doc:`compute dpd ` command if you want the total +conductive energy (:math:`u^{cond}`), internal mechanical +energy (:math:`u^{mech}`), internal chemical energy (:math:`u^{chem}`) +and internal temperatures (:math:`\theta`) for each particle in a group. +See the :doc:`compute dpd ` command if you want the total internal conductive energy, the total internal mechanical energy, the total chemical energy and average internal temperature of the entire system or group of dpd @@ -34,14 +34,16 @@ particles. **Output info:** -This compute calculates a per-particle array with 4 columns (u\_cond, -u\_mech, u\_chem, dpdTheta), which can be accessed by indices 1-4 by any +This compute calculates a per-particle array with 4 columns (:math:`u^{cond}`, +:math:`u^{mech}`, :math:`u^{chem}`, :math:`\theta`), which can be accessed +by indices 1-4 by any command that uses per-particle values from a compute as input. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. -The per-particle array values will be in energy (u\_cond, u\_mech, u\_chem) -and temperature (dpdTheta) :doc:`units `. +The per-particle array values will be in energy (:math:`u^{cond}`, +:math:`u^{mech}`, :math:`u^{chem}`) +and temperature (:math:`theta`) :doc:`units `. Restrictions """""""""""" diff --git a/doc/src/compute_entropy_atom.rst b/doc/src/compute_entropy_atom.rst index 96d55bbb0d..9b4bb5f62b 100644 --- a/doc/src/compute_entropy_atom.rst +++ b/doc/src/compute_entropy_atom.rst @@ -53,27 +53,33 @@ information about the solid structure is required. This parameter for atom i is computed using the following formula from :ref:`(Piaggi) ` and :ref:`(Nettleton) ` , -.. image:: Eqs/pair_entropy.jpg - :align: center +.. math:: + + s_S^i=-2\pi\rho k_B \int\limits_0^{r_m} \left [ g(r) \ln g(r) - g(r) + 1 \right ] r^2 dr + where r is a distance, g(r) is the radial distribution function of atom i and rho is the density of the system. The g(r) computed for each atom i can be noisy and therefore it is smoothed using: -.. image:: Eqs/pair_entropy2.jpg - :align: center +.. math:: + + g_m^i(r) = \frac{1}{4 \pi \rho r^2} \sum\limits_{j} \frac{1}{\sqrt{2 \pi \sigma^2}} e^{-(r-r_{ij})^2/(2\sigma^2)} -where the sum in j goes through the neighbors of atom i, and sigma is a -parameter to control the smoothing. -The input parameters are *sigma* the smoothing parameter, and the -*cutoff* for the calculation of g(r). +where the sum in j goes through the neighbors of atom i, and :math:`\sigma` +is a parameter to control the smoothing. + +The input parameters are *sigma* the smoothing parameter :math:`\sigma`, +and the *cutoff* for the calculation of g(r). If the keyword *avg* has the setting *yes*\ , then this compute also averages the parameter over the neighbors of atom i according to: -.. image:: Eqs/pair_entropy3.jpg - :align: center +.. math:: + + \left< s_S^i \right> = \frac{\sum_j s_S^j + s_S^i}{N + 1} + where the sum j goes over the neighbors of atom i and N is the number of neighbors. This procedure provides a sharper distinction between diff --git a/doc/src/compute_fep.rst b/doc/src/compute_fep.rst index 1cbabef023..84b62a7f4a 100644 --- a/doc/src/compute_fep.rst +++ b/doc/src/compute_fep.rst @@ -70,14 +70,17 @@ initial interactions of the atoms that will undergo perturbation, and a term :math:`U_1` corresponding to the final interactions of these atoms: -.. image:: Eqs/compute_fep_u.jpg - :align: center +.. math:: + + U(\lambda) = U_{\mathrm{bg}} + U_1(\lambda) + U_0(\lambda) A coupling parameter :math:`\lambda` varying from 0 to 1 connects the reference and perturbed systems: -.. image:: Eqs/compute_fep_lambda.jpg - :align: center +.. math:: + + \lambda &= 0 \quad\Rightarrow\quad U = U_{\mathrm{bg}} + U_0 \\ + \lambda &= 1 \quad\Rightarrow\quad U = U_{\mathrm{bg}} + U_1 It is possible but not necessary that the coupling parameter (or a function thereof) appears as a multiplication factor of the potential @@ -89,16 +92,22 @@ This command can be combined with :doc:`fix adapt ` to perform multistage free-energy perturbation calculations along stepwise alchemical transformations during a simulation run: -.. image:: Eqs/compute_fep_fep.jpg - :align: center +.. math:: + + \Delta_0^1 A = \sum_{i=0}^{n-1} \Delta_{\lambda_i}^{\lambda_{i+1}} A = - kT + \sum_{i=0}^{n-1} \ln \left< \exp \left( - \frac{U(\lambda_{i+1}) - + U(\lambda_i)}{kT} \right) \right>_{\lambda_i} This compute is suitable for the finite-difference thermodynamic integration (FDTI) method :ref:`(Mezei) `, which is based on an evaluation of the numerical derivative of the free energy by a perturbation method using a very small :math:`\delta`: -.. image:: Eqs/compute_fep_fdti.jpg - :align: center +.. math:: + + \Delta_0^1 A = \int_{\lambda=0}^{\lambda=1} \left( \frac{\partial + A(\lambda)}{\partial\lambda} \right)_\lambda \mathrm{d}\lambda \approx + \sum_{i=0}^{n-1} w_i \frac{A(\lambda_{i} + \delta) - A(\lambda_i)}{\delta} where :math:`w_i` are weights of a numerical quadrature. The :doc:`fix adapt ` command can be used to define the stages of :math:`\lambda` at which the derivative is calculated and averaged. @@ -109,16 +118,23 @@ choosing a very small perturbation :math:`\delta` the thermodynamic integration method can be implemented using a numerical evaluation of the derivative of the potential energy with respect to :math:`\lambda`: -.. image:: Eqs/compute_fep_ti.jpg - :align: center +.. math:: + + \Delta_0^1 A = \int_{\lambda=0}^{\lambda=1} \left< \frac{\partial + U(\lambda)}{\partial\lambda} \right>_\lambda \mathrm{d}\lambda \approx + \sum_{i=0}^{n-1} w_i \left< \frac{U(\lambda_{i} + \delta) - + U(\lambda_i)}{\delta} \right>_{\lambda_i} Another technique to calculate free energy differences is the acceptance ratio method :ref:`(Bennet) `, which can be implemented by calculating the potential energy differences with :math:`\delta` = 1.0 on both the forward and reverse routes: -.. image:: Eqs/compute_fep_bar.jpg - :align: center +.. math:: + + \left< \frac{1}{1 + \exp\left[\left(U_1 - U_0 - \Delta_0^1A \right) /kT + \right]} \right>_0 = \left< \frac{1}{1 + \exp\left[\left(U_0 - U_1 + + \Delta_0^1A \right) /kT \right]} \right>_1 The value of the free energy difference is determined by numerical root finding to establish the equality. @@ -265,9 +281,11 @@ If the keyword *volume* = *yes*\ , then the Boltzmann term is multiplied by the volume so that correct ensemble averaging can be performed over trajectories during which the volume fluctuates or changes :ref:`(Allen and Tildesley) `: -.. image:: Eqs/compute_fep_vol.jpg - :align: center +.. math:: + \Delta_0^1 A = - kT \sum_{i=0}^{n-1} \ln \frac{\left< V \exp \left( - + \frac{U(\lambda_{i+1}) - U(\lambda_i)}{kT} \right) + \right>_{\lambda_i}}{\left< V \right>_{\lambda_i}} ---------- @@ -314,31 +332,21 @@ The option defaults are *tail* = *no*\ , *volume* = *no*\ . .. _Pearlman: - - **(Pearlman)** Pearlman, J Chem Phys, 98, 1487 (1994) .. _Mezei: - - **(Mezei)** Mezei, J Chem Phys, 86, 7084 (1987) .. _Bennet: - - **(Bennet)** Bennet, J Comput Phys, 22, 245 (1976) .. _BoreschKarplus: - - **(BoreschKarplus)** Boresch and Karplus, J Phys Chem A, 103, 103 (1999) .. _AllenTildesley: - - **(AllenTildesley)** Allen and Tildesley, Computer Simulation of Liquids, Oxford University Press (1987) diff --git a/doc/src/compute_gyration.rst b/doc/src/compute_gyration.rst index 6eb629c85b..fa3b6acbc5 100644 --- a/doc/src/compute_gyration.rst +++ b/doc/src/compute_gyration.rst @@ -32,24 +32,27 @@ periodic boundaries. Rg is a measure of the size of the group of atoms, and is computed as the square root of the Rg\^2 value in this formula -.. image:: Eqs/compute_gyration.jpg - :align: center - -where M is the total mass of the group, Rcm is the center-of-mass -position of the group, and the sum is over all atoms in the group. - -A Rg\^2 tensor, stored as a 6-element vector, is also calculated by -this compute. The formula for the components of the tensor is the -same as the above formula, except that (Ri - Rcm)\^2 is replaced by -(Rix - Rcmx) \* (Riy - Rcmy) for the xy component, etc. The 6 -components of the vector are ordered xx, yy, zz, xy, xz, yz. Note -that unlike the scalar Rg, each of the 6 values of the tensor is -effectively a "squared" value, since the cross-terms may be negative +.. math:: + + {R_g}^2 = \frac{1}{M} \sum_i m_i (r_i - r_{cm})^2 + + +where :math:`M` is the total mass of the group, :math:`r_{cm}` is the +center-of-mass position of the group, and the sum is over all atoms in +the group. + +A :math:`{R_g}^2` tensor, stored as a 6-element vector, is also calculated +by this compute. The formula for the components of the tensor is the +same as the above formula, except that :math:`(r_i - r_{cm})^2` is replaced +by :math:`(r_{i,x} - r_{cm,x}) \cdot (r_{i,y} - r_{cm,y})` for the xy component, +and so on. The 6 components of the vector are ordered xx, yy, zz, xy, xz, yz. +Note that unlike the scalar :math:`R_g`, each of the 6 values of the tensor +is effectively a "squared" value, since the cross-terms may be negative and taking a sqrt() would be invalid. .. note:: - The coordinates of an atom contribute to Rg in "unwrapped" form, + The coordinates of an atom contribute to :math:`R_g` in "unwrapped" form, by using the image flags associated with each atom. See the :doc:`dump custom ` command for a discussion of "unwrapped" coordinates. See the Atoms section of the :doc:`read_data ` command for a discussion of image flags and how they are set for each atom. You can @@ -58,8 +61,8 @@ and taking a sqrt() would be invalid. **Output info:** -This compute calculates a global scalar (Rg) and a global vector of -length 6 (Rg\^2 tensor), which can be accessed by indices 1-6. These +This compute calculates a global scalar (:math:`R_g`) and a global vector of +length 6 (:math:`{R_g}^2` tensor), which can be accessed by indices 1-6. These values can be used by any command that uses a global scalar value or vector values from a compute as input. See the :doc:`Howto output ` doc page for an overview of LAMMPS output options. diff --git a/doc/src/compute_gyration_chunk.rst b/doc/src/compute_gyration_chunk.rst index 4cdb6fa4d6..987cb7fa4c 100644 --- a/doc/src/compute_gyration_chunk.rst +++ b/doc/src/compute_gyration_chunk.rst @@ -52,11 +52,13 @@ boundaries. Rg is a measure of the size of a chunk, and is computed by this formula -.. image:: Eqs/compute_gyration.jpg - :align: center +.. math:: -where M is the total mass of the chunk, Rcm is the center-of-mass -position of the chunk, and the sum is over all atoms in the + {R_g}^2 = \frac{1}{M} \sum_i m_i (r_i - r_{cm})^2 + + +where :math:`M` is the total mass of the chunk, :math:`r_{cm}` is +the center-of-mass position of the chunk, and the sum is over all atoms in the chunk. Note that only atoms in the specified group contribute to the @@ -70,14 +72,16 @@ non-zero chunk IDs. If the *tensor* keyword is specified, then the scalar Rg value is not calculated, but an Rg tensor is instead calculated for each chunk. The formula for the components of the tensor is the same as the above -formula, except that (Ri - Rcm)\^2 is replaced by (Rix - Rcmx) \* (Riy - -Rcmy) for the xy component, etc. The 6 components of the tensor are +formula, except that :math:`(r_i - r_{cm})^2` is replaced by +:math:`(r_{i,x} - r_{cm,x}) \cdot (r_{i,y} - r_{cm,y})` for the xy +component, and so on. The 6 components of the tensor are ordered xx, yy, zz, xy, xz, yz. .. note:: - The coordinates of an atom contribute to Rg in "unwrapped" form, - by using the image flags associated with each atom. See the :doc:`dump custom ` command for a discussion of "unwrapped" coordinates. + The coordinates of an atom contribute to :math:`R_g` in "unwrapped" form, + by using the image flags associated with each atom. See the :doc:`dump custom ` + command for a discussion of "unwrapped" coordinates. See the Atoms section of the :doc:`read_data ` command for a discussion of image flags and how they are set for each atom. You can reset the image flags (e.g. to 0) before invoking this compute by diff --git a/doc/src/compute_gyration_shape.rst b/doc/src/compute_gyration_shape.rst index 590aca59a2..96c0346926 100644 --- a/doc/src/compute_gyration_shape.rst +++ b/doc/src/compute_gyration_shape.rst @@ -33,10 +33,14 @@ due to atoms passing through periodic boundaries. The three computed shape parameters are the asphericity, b, the acylindricity, c, and the relative shape anisotropy, k: -.. image:: Eqs/compute_shape_parameters.jpg - :align: center +.. math:: -where lx <= ly <= lz are the three eigenvalues of the gyration tensor. A general description + c = & l_z - 0.5(l_y+l_x) \\ + b = & l_y - l_x \\ + k = & \frac{3}{2} \frac{l_x^2+l_y^2+l_z^2}{(l_x+l_y+l_z)^2} - \frac{1}{2} + + +where :math:`l_x` <= :math:`l_y` <= :math:`l_z` are the three eigenvalues of the gyration tensor. A general description of these parameters is provided in :ref:`(Mattice) ` while an application to polymer systems can be found in :ref:`(Theodorou) `. The asphericity is always non-negative and zero only when the three principal diff --git a/doc/src/compute_gyration_shape_chunk.rst b/doc/src/compute_gyration_shape_chunk.rst index 309b9d7b6d..72fec2ddc7 100644 --- a/doc/src/compute_gyration_shape_chunk.rst +++ b/doc/src/compute_gyration_shape_chunk.rst @@ -33,10 +33,14 @@ all effects due to atoms passing through periodic boundaries. The three computed shape parameters are the asphericity, b, the acylindricity, c, and the relative shape anisotropy, k: -.. image:: Eqs/compute_shape_parameters.jpg - :align: center +.. math:: -where lx <= ly <= lz are the three eigenvalues of the gyration tensor. A general description + c = & l_z - 0.5(l_y+l_x) \\ + b = & l_y - l_x \\ + k = & \frac{3}{2} \frac{l_x^2+l_y^2+l_z^2}{(l_x+l_y+l_z)^2} - \frac{1}{2} + + +where :math:`l_x` <= :math:`l_y` <= :math`l_z` are the three eigenvalues of the gyration tensor. A general description of these parameters is provided in :ref:`(Mattice) ` while an application to polymer systems can be found in :ref:`(Theodorou) `. The asphericity is always non-negative and zero only when the three principal moments are equal. This zero condition is met when the distribution diff --git a/doc/src/compute_hexorder_atom.rst b/doc/src/compute_hexorder_atom.rst index 66cbcf2409..45560a2aff 100644 --- a/doc/src/compute_hexorder_atom.rst +++ b/doc/src/compute_hexorder_atom.rst @@ -36,19 +36,22 @@ Examples Description """"""""""" -Define a computation that calculates *qn* the bond-orientational +Define a computation that calculates :math:`q_n` the bond-orientational order parameter for each atom in a group. The hexatic (\ *n* = 6) order parameter was introduced by :ref:`Nelson and Halperin ` as a way to detect -hexagonal symmetry in two-dimensional systems. For each atom, *qn* +hexagonal symmetry in two-dimensional systems. For each atom, :math:`q_n` is a complex number (stored as two real numbers) defined as follows: -.. image:: Eqs/hexorder.jpg - :align: center +.. math:: + + q_n = \frac{1}{nnn}\sum_{j = 1}^{nnn} e^{n i \theta({\bf r}_{ij})} + where the sum is over the *nnn* nearest neighbors -of the central atom. The angle theta -is formed by the bond vector rij and the *x* axis. theta is calculated -only using the *x* and *y* components, whereas the distance from the +of the central atom. The angle :math:`\theta` +is formed by the bond vector :math:`r_{ij}` and the *x* axis. +:math:`\theta` is calculated only using the *x* and *y* components, +whereas the distance from the central atom is calculated using all three *x*\ , *y*\ , and *z* components of the bond vector. Neighbor atoms not in the group @@ -60,22 +63,22 @@ the maximum allowable value, is the cutoff specified by the pair style. The optional keyword *nnn* defines the number of nearest -neighbors used to calculate *qn*\ . The default value is 6. +neighbors used to calculate :math:`q_n`. The default value is 6. If the value is NULL, then all neighbors up to the distance cutoff are used. The optional keyword *degree* sets the degree *n* of the order parameter. The default value is 6. For a perfect hexagonal lattice with *nnn* = 6, -*q*\ 6 = exp(6 i phi) for all atoms, where the constant 0 < phi < pi/3 +:math:`q_6 = e^{6 i \phi}` for all atoms, where the constant :math:`0 < \phi < \frac{\pi}{3}` depends only on the orientation of the lattice relative to the *x* axis. In an isotropic liquid, local neighborhoods may still exhibit weak hexagonal symmetry, but because the orientational correlation -decays quickly with distance, the value of phi will be different for -different atoms, and so when *q*\ 6 is averaged over all the atoms -in the system, \|<\ *q*\ 6>\| << 1. +decays quickly with distance, the value of :math:`\phi` will be different for +different atoms, and so when :math:`q_6` is averaged over all the atoms +in the system, :math:`| \left< q_6 \right> | << 1`. -The value of *qn* is set to zero for atoms not in the +The value of :math:`q_n` is set to zero for atoms not in the specified compute group, as well as for atoms that have less than *nnn* neighbors within the distance cutoff. @@ -102,8 +105,8 @@ too frequently. **Output info:** This compute calculates a per-atom array with 2 columns, giving the -real and imaginary parts *qn*\ , a complex number restricted to the -unit disk of the complex plane i.e. Re(\ *qn*\ )\^2 + Im(\ *qn*\ )\^2 <= 1 . +real and imaginary parts :math:`q_n`, a complex number restricted to the +unit disk of the complex plane i.e. :math:`Re(q_n)^2 + Im(q_n)^2 <= 1`. These values can be accessed by any command that uses per-atom values from a compute as input. See the :doc:`Howto output ` doc diff --git a/doc/src/compute_msd_nongauss.rst b/doc/src/compute_msd_nongauss.rst index 180b922097..8168d25ca6 100644 --- a/doc/src/compute_msd_nongauss.rst +++ b/doc/src/compute_msd_nongauss.rst @@ -46,8 +46,10 @@ dz\*dz)\*(dx\*dx + dy\*dy + dz\*dz), summed and averaged over atoms in the group. The 3rd component is the nonGaussian diffusion parameter NGP = 3\*drfourth/(5\*drsquared\*drsquared), i.e. -.. image:: Eqs/compute_msd_nongauss.jpg - :align: center +.. math:: + + NGP(t) = 3<(r(t)-r(0))^4>/(5<(r(t)-r(0))^2>^2) - 1 + The NGP is a commonly used quantity in studies of dynamical heterogeneity. Its minimum theoretical value (-0.4) occurs when all diff --git a/doc/src/compute_orientorder_atom.rst b/doc/src/compute_orientorder_atom.rst index 401f6b46a2..b864db82a7 100644 --- a/doc/src/compute_orientorder_atom.rst +++ b/doc/src/compute_orientorder_atom.rst @@ -42,23 +42,25 @@ Description """"""""""" Define a computation that calculates a set of bond-orientational -order parameters *Ql* for each atom in a group. These order parameters +order parameters :math:`Q_l` for each atom in a group. These order parameters were introduced by :ref:`Steinhardt et al. ` as a way to characterize the local orientational order in atomic structures. -For each atom, *Ql* is a real number defined as follows: +For each atom, :math:`Q_l` is a real number defined as follows: -.. image:: Eqs/orientorder.jpg - :align: center +.. math:: + + \bar{Y}_{lm} = & \frac{1}{nnn}\sum_{j = 1}^{nnn} Y_{lm}( \theta( {\bf r}_{ij} ), \phi( {\bf r}_{ij} ) ) \\ + Q_l = & \sqrt{\frac{4 \pi}{2 l + 1} \sum_{m = -l}^{m = l} \bar{Y}_{lm} \bar{Y}^*_{lm}} The first equation defines the spherical harmonic order parameters. These are complex number components of the 3D analog of the 2D order -parameter *qn*\ , which is implemented as LAMMPS compute +parameter :math:`q_n`, which is implemented as LAMMPS compute :doc:`hexorder/atom `. The summation is over the *nnn* nearest neighbors of the central atom. The angles theta and phi are the standard spherical polar angles -defining the direction of the bond vector *rij*\ . -The second equation defines *Ql*\ , which is a +defining the direction of the bond vector :math:`r_{ij}`. +The second equation defines :math:`Q_l`, which is a rotationally invariant non-negative amplitude obtained by summing over all the components of degree *l*\ . @@ -68,42 +70,45 @@ the maximum allowable value, is the cutoff specified by the pair style. The optional keyword *nnn* defines the number of nearest -neighbors used to calculate *Ql*\ . The default value is 12. +neighbors used to calculate :math:`Q_l`. The default value is 12. If the value is NULL, then all neighbors up to the specified distance cutoff are used. The optional keyword *degrees* defines the list of order parameters to be computed. The first argument *nlvalues* is the number of order parameters. This is followed by that number of non-negative integers giving the -degree of each order parameter. Because *Q*\ 2 and all odd-degree order +degree of each order parameter. Because :math:`Q_2` and all odd-degree order parameters are zero for atoms in cubic crystals (see -:ref:`Steinhardt `), the default order parameters are *Q*\ 4, -*Q*\ 6, *Q*\ 8, *Q*\ 10, and *Q*\ 12. For the FCC crystal with *nnn* =12, *Q*\ 4 -= sqrt(7/3)/8 = 0.19094.... The numerical values of all order -parameters up to *Q*\ 12 for a range of commonly encountered -high-symmetry structures are given in Table I of :ref:`Mickel et al. `, and these can be reproduced with this compute - -The optional keyword *wl* will output the third-order invariants *Wl* +:ref:`Steinhardt `), the default order parameters are :math:`Q_4`, +:math:`Q_6`, :math:`Q_8`, :math:`Q_{10}`, and :math:`Q_{12}`. For the FCC +crystal with *nnn* =12, :math:`Q_4 = \sqrt{\frac{7}{192}} = 0.19094...`. +The numerical values of all order +parameters up to :math:`Q_12` for a range of commonly encountered +high-symmetry structures are given in Table I of :ref:`Mickel et al. `, +and these can be reproduced with this compute. + +The optional keyword *wl* will output the third-order invariants :math:`W_l` (see Eq. 1.4 in :ref:`Steinhardt `) for the same degrees as -for the *Ql* parameters. For the FCC crystal with *nnn* =12, -*W*\ 4 = -sqrt(14/143).(49/4096)/Pi\^1.5 = -0.0006722136... +for the :math:`Q_l` parameters. For the FCC crystal with *nnn* =12, +:math:`W_4` = -sqrt(14/143).(49/4096)/Pi\^1.5 = -0.0006722136... The optional keyword *wl/hat* will output the normalized third-order -invariants *Wlhat* (see Eq. 2.2 in :ref:`Steinhardt `) -for the same degrees as for the *Ql* parameters. For the FCC crystal -with *nnn* =12, *W*\ 4hat = -7/3\*sqrt(2/429) = -0.159317...The numerical -values of *Wlhat* for a range of commonly encountered high-symmetry +invariants :math:`\hat{W}_l` (see Eq. 2.2 in :ref:`Steinhardt `) +for the same degrees as for the :math:`Q_l` parameters. For the FCC crystal +with *nnn* =12, :math:`\hat{W}_4 = -\frac{7}{3} \sqrt{\frac{2}{429}} = -0.159317...` +The numerical +values of :math:`\hat{W}_l` for a range of commonly encountered high-symmetry structures are given in Table I of :ref:`Steinhardt `, and these can be reproduced with this keyword. The optional keyword *components* will output the components of the -normalized complex vector *Ybar\_lm* of degree *ldegree*\ , which must be +normalized complex vector :math:`\bar{Y}_{lm}` of degree *ldegree*\ , which must be explicitly included in the keyword *degrees*\ . This option can be used in conjunction with :doc:`compute coord\_atom ` to calculate the ten Wolde's criterion to identify crystal-like particles, as discussed in :ref:`ten Wolde `. -The value of *Ql* is set to zero for atoms not in the +The value of :math:`Q_l` is set to zero for atoms not in the specified compute group, as well as for atoms that have less than *nnn* neighbors within the distance cutoff, unless *nnn* is NULL. @@ -130,19 +135,19 @@ too frequently. **Output info:** This compute calculates a per-atom array with *nlvalues* columns, -giving the *Ql* values for each atom, which are real numbers on the -range 0 <= *Ql* <= 1. +giving the :math:`Q_l` values for each atom, which are real numbers on the +range :math:`0 <= Q_l <= 1`. -If the keyword *wl* is set to yes, then the *Wl* values for each +If the keyword *wl* is set to yes, then the :math:`W_l` values for each atom will be added to the output array, which are real numbers. -If the keyword *wl/hat* is set to yes, then the *Wl\_hat* +If the keyword *wl/hat* is set to yes, then the :math:`\hat{W}_l` values for each atom will be added to the output array, which are real numbers. If the keyword *components* is set, then the real and imaginary parts -of each component of (normalized) *Ybar\_lm* will be added to the -output array in the following order: Re(*Ybar\_-m*) Im(*Ybar\_-m*) -Re(*Ybar\_-m+1*) Im(*Ybar\_-m+1*) ... Re(*Ybar\_m*) Im(*Ybar\_m*). This +of each component of (normalized) :math:`\bar{Y}_{lm}` will be added to the +output array in the following order: :math:`Re(\bar{Y}_{-m}) Im(\bar{Y}_{-m}) +Re(\bar{Y}_{-m+1}) Im(\bar{Y}_{-m+1}) ... Re(\bar{Y}_m) Im(\bar{Y}_m)`. This way, the per-atom array will have a total of *nlvalues*\ +2\*(2\ *l*\ +1) columns. @@ -163,7 +168,7 @@ Default """"""" The option defaults are *cutoff* = pair style cutoff, *nnn* = 12, -*degrees* = 5 4 6 8 10 12 i.e. *Q*\ 4, *Q*\ 6, *Q*\ 8, *Q*\ 10, and *Q*\ 12, +*degrees* = 5 4 6 8 10 12 i.e. :math:`Q_4`, :math:`Q_6`, :math:`Q_8`, :math:`Q_{10}`, and :math:`Q_{12}`, *wl* = no, *wl/hat* = no, and *components* off @@ -172,21 +177,16 @@ The option defaults are *cutoff* = pair style cutoff, *nnn* = 12, .. _Steinhardt: - - **(Steinhardt)** P. Steinhardt, D. Nelson, and M. Ronchetti, Phys. Rev. B 28, 784 (1983). .. _Mickel: - - **(Mickel)** W. Mickel, S. C. Kapfer, G. E. Schroeder-Turkand, K. Mecke, J. Chem. Phys. 138, 044501 (2013). .. _tenWolde2: - **(tenWolde)** P. R. ten Wolde, M. J. Ruiz-Montero, D. Frenkel, J. Chem. Phys. 104, 9932 (1996). diff --git a/doc/src/compute_pressure.rst b/doc/src/compute_pressure.rst index c6530ed11e..ed3b90c8e1 100644 --- a/doc/src/compute_pressure.rst +++ b/doc/src/compute_pressure.rst @@ -37,8 +37,10 @@ of atoms via the :doc:`compute reduce ` command. The pressure is computed by the formula -.. image:: Eqs/pressure.jpg - :align: center +.. math:: + + P = \frac{N k_B T}{V} + \frac{\sum_{i}^{N'} r_i \bullet f_i}{dV} + where N is the number of atoms in the system (see discussion of DOF below), Kb is the Boltzmann constant, T is the temperature, d is the @@ -62,8 +64,11 @@ ordered xx, yy, zz, xy, xz, yz. The equation for the I,J components the first term uses components of the kinetic energy tensor and the second term uses components of the virial tensor: -.. image:: Eqs/pressure_tensor.jpg - :align: center +.. math:: + + P_{IJ} = \frac{\sum_{k}^{N} m_k v_{k_I} v_{k_J}}{V} + + \frac{\sum_{k}^{N'} r_{k_I} f_{k_J}}{V} + If no extra keywords are listed, the entire equations above are calculated. This includes a kinetic energy (temperature) term and the diff --git a/doc/src/compute_ptm_atom.rst b/doc/src/compute_ptm_atom.rst index e7667adae9..1b5066e473 100644 --- a/doc/src/compute_ptm_atom.rst +++ b/doc/src/compute_ptm_atom.rst @@ -62,8 +62,11 @@ to identify potential structure matches. Next, the deviation is computed betwee local structure (in the simulation) and a template of the ideal lattice structure. The deviation is calculated as: -.. image:: Eqs/ptm_rmsd.jpg - :align: center +.. math:: + + \text{RMSD}(\mathbf{u}, \mathbf{v}) = \min_{s, \mathbf{Q}} \sqrt{\frac{1}{N} \sum\limits_{i=1}^{N} + {\left|\left| s[\vec{u_i} - \overline{\mathbf{u}}] - \mathbf{Q} \vec{v_i} \right|\right|}^2} + Here, u and v contain the coordinates of the local and ideal structures respectively, s is a scale factor, and Q is a rotation. The best match is identified by the diff --git a/doc/src/compute_saed.rst b/doc/src/compute_saed.rst index 9b4067043f..2a9c05f218 100644 --- a/doc/src/compute_saed.rst +++ b/doc/src/compute_saed.rst @@ -59,14 +59,14 @@ radiation of wavelength lambda. The electron diffraction intensity I at each reciprocal lattice point is computed from the structure factor F using the equations: -.. image:: Eqs/compute_saed1.jpg - :align: center +.. math:: + + I = & \frac{F^{*}F}{N} \\ + F(\mathbf{k}) = & \sum_{j=1}^{N}f_j(\theta)exp(2\pi i \mathbf{k} \cdot \mathbf{r}_j) -.. image:: Eqs/compute_saed2.jpg - :align: center -Here, K is the location of the reciprocal lattice node, rj is the -position of each atom, fj are atomic scattering factors. +Here, K is the location of the reciprocal lattice node, :math:`r_j` is the +position of each atom, :math:`f_j` are atomic scattering factors. Diffraction intensities are calculated on a three-dimensional mesh of reciprocal lattice nodes. The mesh spacing is defined either (a) by @@ -119,33 +119,117 @@ for each atom type (type1 type2 ... typeN) and angle of diffraction. The analytic approximation is computed using the formula :ref:`(Brown) `: -.. image:: Eqs/compute_saed3.jpg - :align: center +.. math:: + + f_j\left ( \frac{sin(\theta)}{\lambda} \right )=\sum_{i}^{5} + a_i exp\left ( -b_i \frac{sin^{2}(\theta)}{\lambda^{2}} \right ) + Coefficients parameterized by :ref:`(Fox) ` are assigned for each atom type designating the chemical symbol and charge of each atom type. Valid chemical symbols for compute saed are: -H: He: Li: Be: B: -C: N: O: F: Ne: -Na: Mg: Al: Si: P: -S: Cl: Ar: K: Ca: -Sc: Ti: V: Cr: Mn: -Fe: Co: Ni: Cu: Zn: -Ga: Ge: As: Se: Br: -Kr: Rb: Sr: Y: Zr: -Nb: Mo: Tc: Ru: Rh: -Pd: Ag: Cd: In: Sn: -Sb: Te: I: Xe: Cs: -Ba: La: Ce: Pr: Nd: -Pm: Sm: Eu: Gd: Tb: -Dy: Ho: Er: Tm: Yb: -Lu: Hf: Ta: W: Re: -Os: Ir: Pt: Au: Hg: -Tl: Pb: Bi: Po: At: -Rn: Fr: Ra: Ac: Th: -Pa: U: Np: Pu: Am: -Cm: Bk: Cf:tb(c=5,s=:) +.. table_from_list:: + :columns: 20 + + * H + * He + * Li + * Be + * B + * C + * N + * O + * F + * Ne + * Na + * Mg + * Al + * Si + * P + * S + * Cl + * Ar + * K + * Ca + * Sc + * Ti + * V + * Cr + * Mn + * Fe + * Co + * Ni + * Cu + * Zn + * Ga + * Ge + * As + * Se + * Br + * Kr + * Rb + * Sr + * Y + * Zr + * Nb + * Mo + * Tc + * Ru + * Rh + * Pd + * Ag + * Cd + * In + * Sn + * Sb + * Te + * I + * Xe + * Cs + * Ba + * La + * Ce + * Pr + * Nd + * Pm + * Sm + * Eu + * Gd + * Tb + * Dy + * Ho + * Er + * Tm + * Yb + * Lu + * Hf + * Ta + * W + * Re + * Os + * Ir + * Pt + * Au + * Hg + * Tl + * Pb + * Bi + * Po + * At + * Rn + * Fr + * Ra + * Ac + * Th + * Pa + * U + * Np + * Pu + * Am + * Cm + * Bk + * Cf If the *echo* keyword is specified, compute saed will provide extra reporting information to the screen. diff --git a/doc/src/compute_sna_atom.rst b/doc/src/compute_sna_atom.rst index be3deaf36a..6da3ab45ea 100644 --- a/doc/src/compute_sna_atom.rst +++ b/doc/src/compute_sna_atom.rst @@ -82,8 +82,10 @@ onto the 3-sphere, the surface of the unit ball in a four-dimensional space. The radial distance *r* within *R\_ii'* is mapped on to a third polar angle *theta0* defined by, -.. image:: Eqs/compute_sna_atom1.jpg - :align: center +.. math:: + + \theta_0 = {\tt rfac0} \frac{r-r_{min0}}{R_{ii'}-r_{min0}} \pi + In this way, all possible neighbor positions are mapped on to a subset of the 3-sphere. Points south of the latitude *theta0max=rfac0\*Pi* @@ -101,8 +103,10 @@ radial distance. Expanding this density function as a generalized Fourier series in the basis functions, we can write each Fourier coefficient as -.. image:: Eqs/compute_sna_atom2.jpg - :align: center +.. math:: + + u^j_{m,m'} = U^j_{m,m'}(0,0,0) + \sum_{r_{ii'} < R_{ii'}}{f_c(r_{ii'}) w_{i'} U^j_{m,m'}(\theta_0,\theta,\phi)} + The *w\_i'* neighbor weights are dimensionless numbers that are chosen to distinguish atoms of different types, while the central atom is @@ -110,8 +114,11 @@ arbitrarily assigned a unit weight. The function *fc(r)* ensures that the contribution of each neighbor atom goes smoothly to zero at *R\_ii'*: -.. image:: Eqs/compute_sna_atom4.jpg - :align: center +.. math:: + + f_c(r) = & \frac{1}{2}(\cos(\pi \frac{r-r_{min0}}{R_{ii'}-r_{min0}}) + 1), r \leq R_{ii'} \\ + = & 0, r > R_{ii'} + The expansion coefficients *u\^j\_m,m'* are complex-valued and they are not directly useful as descriptors, because they are not invariant @@ -119,8 +126,15 @@ under rotation of the polar coordinate frame. However, the following scalar triple products of expansion coefficients can be shown to be real-valued and invariant under rotation :ref:`(Bartok) `. -.. image:: Eqs/compute_sna_atom3.jpg - :align: center +.. math:: + + B_{j_1,j_2,j} = + \sum_{m_1,m'_1=-j_1}^{j_1}\sum_{m_2,m'_2=-j_2}^{j_2}\sum_{m,m'=-j}^{j} (u^j_{m,m'})^* + H {\scriptscriptstyle \begin{array}{l} {j} {m} {m'} \\ + {j_1} {m_1} {m'_1} \\ + {j_2} {m_2} {m'_2} \end{array}} + u^{j_1}_{m_1,m'_1} u^{j_2}_{m_2,m'_2} + The constants *H\^jmm'\_j1m1m1'\_j2m2m2'* are coupling coefficients, analogous to Clebsch-Gordan coefficients for rotations on the @@ -138,8 +152,10 @@ atom. Compute *snad/atom* calculates the derivative of the bispectrum components summed separately for each atom type: -.. image:: Eqs/compute_sna_atom5.jpg - :align: center +.. math:: + + -\sum_{i' \in I} \frac{\partial {B^{i'}_{j_1,j_2,j} }}{\partial {\bf r}_i} + The sum is over all atoms *i'* of atom type *I*\ . For each atom *i*\ , this compute evaluates the above expression for each direction, each @@ -149,8 +165,10 @@ for a detailed explanation. Compute *snav/atom* calculates the virial contribution due to the derivatives: -.. image:: Eqs/compute_sna_atom6.jpg - :align: center +.. math:: + + -{\bf r}_i \otimes \sum_{i' \in I} \frac{\partial {B^{i'}_{j_1,j_2,j}}}{\partial {\bf r}_i} + Again, the sum is over all atoms *i'* of atom type *I*\ . For each atom *i*\ , this compute evaluates the above expression for each of the six @@ -233,7 +251,7 @@ ordered in which they are listed. file. The rerun script can use a :doc:`special_bonds ` command that includes all pairs in the neighbor list. -;line +---------- **Output info:** diff --git a/doc/src/compute_xrd.rst b/doc/src/compute_xrd.rst index b7ed547572..d95fad79e4 100644 --- a/doc/src/compute_xrd.rst +++ b/doc/src/compute_xrd.rst @@ -57,21 +57,16 @@ of wavelength lambda. The x-ray diffraction intensity, I, at each reciprocal lattice point, k, is computed from the structure factor, F, using the equations: -.. image:: Eqs/compute_xrd1.jpg - :align: center - -.. image:: Eqs/compute_xrd2.jpg - :align: center - -.. image:: Eqs/compute_xrd3.jpg - :align: center +.. math:: -.. image:: Eqs/compute_xrd4.jpg - :align: center + I = & Lp(\theta)\frac{F^{*}F}{N} \\ + F(\mathbf{k}) = & \sum_{j=1}^{N}f_j(\theta)exp(2\pi i \mathbf{k}\cdot \mathbf{r}_j) \\ + Lp(\theta) = & \frac{1+cos^{2}(2\theta)}{cos(\theta)sin^{2}(\theta)} \\ + \frac{sin(\theta)}{\lambda} = & \frac{\left | \mathbf{k} \right |}{2} -Here, K is the location of the reciprocal lattice node, rj is the -position of each atom, fj are atomic scattering factors, LP is the -Lorentz-polarization factor, and theta is the scattering angle of +Here, K is the location of the reciprocal lattice node, :math:`r_j` is the +position of each atom, :math:`f_j` are atomic scattering factors, *Lp* is the +Lorentz-polarization factor, and :math:`\theta` is the scattering angle of diffraction. The Lorentz-polarization factor can be turned off using the optional *LP* keyword. @@ -114,8 +109,10 @@ for each atom type (type1 type2 ... typeN) and angle of diffraction. The analytic approximation is computed using the formula :ref:`(Colliex) `: -.. image:: Eqs/compute_xrd5.jpg - :align: center +.. math:: + + f_j\left ( \frac{sin(\theta)}{\lambda} \right )=\sum_{i}^{4} + a_i exp\left ( -b_i \frac{sin^{2}(\theta)}{\lambda^{2}} \right )+c Coefficients parameterized by :ref:`(Peng) ` are assigned for each atom type designating the chemical symbol and charge of each atom diff --git a/doc/src/fix_ave_correlate_long.rst b/doc/src/fix_ave_correlate_long.rst index 6c9d7c076b..dd84daaa75 100644 --- a/doc/src/fix_ave_correlate_long.rst +++ b/doc/src/fix_ave_correlate_long.rst @@ -70,11 +70,12 @@ Examples Description """"""""""" -This fix is similar in spirit and syntax to the :doc:`fix ave/correlate `. However, this fix allows the -efficient calculation of time correlation functions on the fly over -extremely long time windows without too much CPU overhead, using a -multiple-tau method :ref:`(Ramirez) ` that decreases the resolution -of the stored correlation function with time. +This fix is similar in spirit and syntax to the :doc:`fix ave/correlate `. +However, this fix allows the efficient calculation of time correlation +functions on-the-fly over extremely long time windows with little +additional CPU overhead, using a multiple-tau method +:ref:`(Ramirez) ` that decreases the resolution of the stored +correlation function with time. It is not a full drop-in replacement. The group specified with this command is ignored. However, note that specified values may represent calculations performed by computes and @@ -115,11 +116,13 @@ For the meaning of the additional optional keywords, see the :doc:`fix ave/corre **Restart, fix\_modify, output, run start/stop, minimize info:** -Since this fix in intended for the calculation of time correlation -functions over very long MD simulations, the information about this -fix is written automatically to binary restart files, so that the time -correlation calculation can continue in subsequent simulations. None -of the fix\_modify options are relevant to this fix. +Contrary to doc:`fix ave/correlate `_ this fix +does **not** provide access to its internal data to various output +options. Since this fix in intended for the calculation of time +correlation functions over very long MD simulations, the information +about this fix is written automatically to binary restart files, so +that the time correlation calculation can continue in subsequent +simulations. None of the fix\_modify options are relevant to this fix. No parameter of this fix can be used with the start/stop keywords of the run command. This fix is not invoked during energy minimization. diff --git a/doc/src/fix_bond_react.rst b/doc/src/fix_bond_react.rst index ec431168b8..14d04009e7 100644 --- a/doc/src/fix_bond_react.rst +++ b/doc/src/fix_bond_react.rst @@ -374,8 +374,10 @@ reacting molecules. The constraint of type 'arrhenius' imposes an additional reaction probability according to the temperature-dependent Arrhenius equation: -.. image:: Eqs/fix_bond_react.jpg - :align: center +.. math:: + + k = AT^{n}e^{\frac{-E_{a}}{k_{B}T}} + The Arrhenius constraint has the following syntax: @@ -385,8 +387,8 @@ The Arrhenius constraint has the following syntax: arrhenius *A* *n* *E_a* *seed* where 'arrhenius' is the required keyword, *A* is the pre-exponential -factor, *n* is the exponent of the temperature dependence, *E\_a* is -the activation energy (:doc:`units ` of energy), and *seed* is a +factor, *n* is the exponent of the temperature dependence, :math:`E_a` +is the activation energy (:doc:`units ` of energy), and *seed* is a random number seed. The temperature is defined as the instantaneous temperature averaged over all atoms in the reaction site, and is calculated in the same manner as for example diff --git a/doc/src/fix_box_relax.rst b/doc/src/fix_box_relax.rst index d915d1a2a0..0c4cad7ad0 100644 --- a/doc/src/fix_box_relax.rst +++ b/doc/src/fix_box_relax.rst @@ -228,23 +228,28 @@ With this fix, the potential energy used by the minimizer is augmented by an additional energy provided by the fix. The overall objective function then is: -.. image:: Eqs/fix_box_relax1.jpg - :align: center +.. math:: -where *U* is the system potential energy, *P*\ \_t is the desired -hydrostatic pressure, *V* and *V*\ \_0 are the system and reference -volumes, respectively. *E*\ \_\ *strain* is the strain energy expression + E = U + P_t \left(V-V_0 \right) + E_{strain} + + +where *U* is the system potential energy, :math:`P_t` is the desired +hydrostatic pressure, :math:`V` and :math:`V_0` are the system and reference +volumes, respectively. :math:`E_{strain}` is the strain energy expression proposed by Parrinello and Rahman :ref:`(Parrinello1981) `. Taking derivatives of *E* w.r.t. the box dimensions, and setting these to zero, we find that at the minimum of the objective function, the global system stress tensor **P** will satisfy the relation: -.. image:: Eqs/fix_box_relax2.jpg - :align: center +.. math:: + + \mathbf P = P_t \mathbf I + {\mathbf S_t} \left( \mathbf h_0^{-1} \right)^t \mathbf h_{0d} + -where **I** is the identity matrix, **h**\ \_0 is the box dimension tensor of -the reference cell, and **h**\ \_0\ *d* is the diagonal part of -**h**\ \_0. **S**\ \_\ *t* is a symmetric stress tensor that is chosen by LAMMPS +where **I** is the identity matrix, :math:`\mathbf{h_0}` is the box +dimension tensor of the reference cell, and ::math:`\mathbf{h_{0d}}` +is the diagonal part of :math:`\mathbf{h_0}`. :math:`\mathbf{S_t}` +is a symmetric stress tensor that is chosen by LAMMPS so that the upper-triangular components of **P** equal the stress tensor specified by the user. diff --git a/doc/src/fix_controller.rst b/doc/src/fix_controller.rst index 7561df6856..839c01ef5f 100644 --- a/doc/src/fix_controller.rst +++ b/doc/src/fix_controller.rst @@ -97,43 +97,49 @@ The PID controller is invoked once each *Nevery* timesteps. The PID controller is implemented as a discretized version of the following dynamic equation: -.. image:: Eqs/fix_controller1.jpg - :align: center +.. math:: + \frac{dc}{dt} = \hat{E} -\alpha (K_p e + K_i \int_0^t e \, dt + K_d \frac{de}{dt} ) + where *c* is the continuous time analog of the control variable, *e* =\ *pvar*\ -\ *setpoint* is the error in the process variable, and -*alpha*\ , *Kp*\ , *Ki*\ , and *Kd* are constants set by the corresponding +:math:`\alpha`, :math:`K_p`, :math:`K_i` , and :math:`K_d` are constants +set by the corresponding keywords described above. The discretized version of this equation is: -.. image:: Eqs/fix_controller2.jpg - :align: center +.. math:: -where *tau* = *Nevery* \* *timestep* is the time interval between updates, + c_n = \hat{E} c_{n-1} -\alpha \left( K_p \tau e_n + K_i \tau^2 \sum_{i=1}^n e_i + K_d (e_n - e_{n-1}) \right) + + +where :math:`\tau = \mathtt{Nevery} \cdot \mathtt{timestep}` is the time +interval between updates, and the subscripted variables indicate the values of *c* and *e* at successive updates. From the first equation, it is clear that if the three gain values -*Kp*\ , *Ki*\ , *Kd* are dimensionless constants, then *alpha* must have +:math:`K_p`, :math:`K_i`, :math:`K_d` are dimensionless constants, +then :math:`\alpha` must have units of [unit *cvar*\ ]/[unit *pvar*\ ]/[unit time] e.g. [ eV/K/ps ]. The advantage of this unit scheme is that the value of the constants should be invariant under a change of either the MD timestep size or the value of *Nevery*\ . Similarly, if the LAMMPS :doc:`unit style ` is changed, it should only be necessary to change -the value of *alpha* to reflect this, while leaving *Kp*\ , *Ki*\ , and -*Kd* unaltered. +the value of :math:`\alpha` to reflect this, while leaving :math:`K_p`, +:math:`K_i`, and :math:`K_d` unaltered. When choosing the values of the four constants, it is best to first -pick a value and sign for *alpha* that is consistent with the -magnitudes and signs of *pvar* and *cvar*\ . The magnitude of *Kp* -should then be tested over a large positive range keeping *Ki* = *Kd* =0. -A good value for *Kp* will produce a fast response in *pvar*\ , without -overshooting the *setpoint*\ . For many applications, proportional -feedback is sufficient, and so *Ki* = *Kd* =0 can be used. In cases where -there is a substantial lag time in the response of *pvar* to a change -in *cvar*\ , this can be counteracted by increasing *Kd*\ . In situations +pick a value and sign for :math:`\alpha` that is consistent with the +magnitudes and signs of *pvar* and *cvar*\ . The magnitude of :math:`K_p` +should then be tested over a large positive range keeping :math:`K_i = K_d =0`. +A good value for :math:`K_p` will produce a fast response in *pvar*\ , +without overshooting the *setpoint*\ . For many applications, proportional +feedback is sufficient, and so :math:`K_i` = K_d =0` can be used. In cases +where there is a substantial lag time in the response of *pvar* to a change +in *cvar*\ , this can be counteracted by increasing :math:`K_d`. In situations where *pvar* plateaus without reaching *setpoint*\ , this can be -counteracted by increasing *Ki*\ . In the language of Charles Dickens, -*Kp* represents the error of the present, *Ki* the error of the past, -and *Kd* the error yet to come. +counteracted by increasing :math:`K_i`. In the language of Charles Dickens, +:math:`K_p` represents the error of the present, :math:`K_i` the error of +the past, and :math:`K_d` the error yet to come. Because this fix updates *cvar*\ , but does not initialize its value, the initial value is that assigned by the user in the input script via @@ -141,7 +147,7 @@ the :doc:`internal-style variable ` command. This value is used (by the other LAMMPS command that used the variable) until this fix performs its first update of *cvar* after *Nevery* timesteps. On the first update, the value of the derivative term is set to zero, -because the value of *e\_n-1* is not yet defined. +because the value of :math:`e_n-1` is not yet defined. ---------- diff --git a/doc/src/fix_ehex.rst b/doc/src/fix_ehex.rst index 34445fd284..9cc02261c7 100644 --- a/doc/src/fix_ehex.rst +++ b/doc/src/fix_ehex.rst @@ -78,13 +78,20 @@ additional thermostatting force to the equations of motion, such that the time evolution of coordinates and momenta of particle :math:`i` becomes :ref:`(Wirnsberger) ` -.. image:: Eqs/fix_ehex_eom.jpg - :align: center +.. math:: + + \dot{\mathbf r}_i &= \mathbf v_i, \\ + \dot{\mathbf v}_i &= \frac{\mathbf f_i}{m_i} + \frac{\mathbf g_i}{m_i}. The thermostatting force is given by -.. image:: Eqs/fix_ehex_f.jpg - :align: center +.. math:: + + \mathbf g_i = \begin{cases} + \frac{m_i}{2} \frac{ F_{\Gamma_{k(\mathbf r_i)}}}{ K_{\Gamma_{k(\mathbf r_i)}}} + \left(\mathbf v_i - \mathbf v_{\Gamma_{k(\mathbf r_i)}} \right) & \mbox{$k(\mathbf r_i)> 0$ (inside a reservoir),} \\ + 0 & \mbox{otherwise, } + \end{cases} where :math:`m_i` is the mass and :math:`k(\mathbf r_i)` maps the particle position to the respective reservoir. The quantity diff --git a/doc/src/fix_eos_cv.rst b/doc/src/fix_eos_cv.rst index b871429ffa..da1459970f 100644 --- a/doc/src/fix_eos_cv.rst +++ b/doc/src/fix_eos_cv.rst @@ -27,17 +27,19 @@ Description """"""""""" Fix *eos/cv* applies a mesoparticle equation of state to relate the -particle internal energy (u\_i) to the particle internal temperature -(dpdTheta\_i). The *eos/cv* mesoparticle equation of state requires +particle internal energy (:math:`u_i`) to the particle internal temperature +(:math:`\theta_i`). The *eos/cv* mesoparticle equation of state requires the constant-volume heat capacity, and is defined as follows: -.. image:: Eqs/fix_eos-cv.jpg - :align: center +.. math:: -where Cv is the constant-volume heat capacity, u\_cond is the internal -conductive energy, and u\_mech is the internal mechanical energy. Note -that alternative definitions of the mesoparticle equation of state are -possible. + u_{i} = u^{mech}_{i} + u^{cond}_{i} = C_{V} \theta_{i} + + +where :math:`C_V` is the constant-volume heat capacity, :math:`u^{cond}` +is the internal conductive energy, and :math:`u^{mech}` is the internal +mechanical energy. Note that alternative definitions of the mesoparticle +equation of state are possible. ---------- diff --git a/doc/src/fix_eos_table_rx.rst b/doc/src/fix_eos_table_rx.rst index a41ac404b7..681b656b53 100644 --- a/doc/src/fix_eos_table_rx.rst +++ b/doc/src/fix_eos_table_rx.rst @@ -40,30 +40,34 @@ Description Fix *eos/table/rx* applies a tabulated mesoparticle equation of state to relate the concentration-dependent particle internal -energy (u\_i) to the particle internal temperature (dpdTheta\_i). +energy (:math:`u_i`) to the particle internal temperature (:math:`\theta_i`). -The concentration-dependent particle internal energy (u\_i) is +The concentration-dependent particle internal energy (:math:`u_i`) is computed according to the following relation: -.. image:: Eqs/fix_eos_table_rx.jpg - :align: center +.. math:: -where *m* is the number of species, *c\_i,j* is the concentration of -species *j* in particle *i*\ , *u\_j* is the internal energy of species j, -*DeltaH\_f,j* is the heat of formation of species *j*\ , N is the number of -molecules represented by the coarse-grained particle, kb is the -Boltzmann constant, and T is the temperature of the system. Additionally, -it is possible to modify the concentration-dependent particle internal + U_{i} = \displaystyle\sum_{j=1}^{m} c_{i,j}(u_{j} + \Delta H_{f,j}) + \frac{3k_{b}T}{2} + Nk_{b}T \\ + + +where *m* is the number of species, :math:`c_{i,j}` is the +concentration of species *j* in particle *i*\ , :math:`u_j` is the +internal energy of species j, :math:`\Delta H_{f,j} is the heat of +formation of species *j*\ , N is the number of molecules represented +by the coarse-grained particle, :math:`k_b` is the Boltzmann constant, +and *T* is the temperature of the system. Additionally, it is +possible to modify the concentration-dependent particle internal energy relation by adding an energy correction, temperature-dependent -correction, and/or a molecule-dependent correction. An energy correction can -be specified as a constant (in energy units). A temperature correction can be -specified by multiplying a temperature correction coefficient by the -internal temperature. A molecular correction can be specified by -by multiplying a molecule correction coefficient by the average number of -product gas particles in the coarse-grain particle. +correction, and/or a molecule-dependent correction. An energy +correction can be specified as a constant (in energy units). A +temperature correction can be specified by multiplying a temperature +correction coefficient by the internal temperature. A molecular +correction can be specified by by multiplying a molecule correction +coefficient by the average number of product gas particles in the +coarse-grain particle. Fix *eos/table/rx* creates interpolation tables of length *N* from *m* -internal energy values of each species *u\_j* listed in a file as a +internal energy values of each species :math:`u_j` listed in a file as a function of internal temperature. During a simulation, these tables are used to interpolate internal energy or temperature values as needed. The interpolation is done with the *linear* style. For the *linear* style, @@ -72,20 +76,21 @@ which an internal energy is computed by linear interpolation. A secant solver is used to determine the internal temperature from the internal energy. The first filename specifies a file containing tabulated internal -temperature and *m* internal energy values for each species *u\_j*. +temperature and *m* internal energy values for each species :math:`u_j`. The keyword specifies a section of the file. The format of this file is described below. The second filename specifies a file containing heat of formation -*DeltaH\_f,j* for each species. +:math:`\Delta H_{f,j}` for each species. In cases where the coarse-grain particle represents a single molecular -species (i.e., no reactions occur and fix *rx* is not present in the input file), -fix *eos/table/rx* can be applied in a similar manner to fix *eos/table* -within a non-reactive DPD simulation. In this case, the heat of formation -filename is replaced with the heat of formation value for the single species. -Additionally, the energy correction and temperature correction coefficients may -also be specified as fix arguments. +species (i.e., no reactions occur and fix *rx* is not present in the +input file), fix *eos/table/rx* can be applied in a similar manner to +fix *eos/table* within a non-reactive DPD simulation. In this case, +the heat of formation filename is replaced with the heat of formation +value for the single species. Additionally, the energy correction and +temperature correction coefficients may also be specified as fix +arguments. ---------- diff --git a/doc/src/fix_gcmc.rst b/doc/src/fix_gcmc.rst index a0717dd6ae..dd06d074a4 100644 --- a/doc/src/fix_gcmc.rst +++ b/doc/src/fix_gcmc.rst @@ -248,8 +248,10 @@ two groups: the default group "all" and the fix group The chemical potential is a user-specified input parameter defined as: -.. image:: Eqs/fix_gcmc1.jpg - :align: center +.. math:: + + \mu = \mu^{id} + \mu^{ex} + The second term mu\_ex is the excess chemical potential due to energetic interactions and is formally zero for the fictitious gas @@ -260,31 +262,35 @@ quite different. The first term mu\_id is the ideal gas contribution to the chemical potential. mu\_id can be related to the density or pressure of the fictitious gas reservoir by: -.. image:: Eqs/fix_gcmc2.jpg - :align: center +.. math:: + + \mu^{id} = & k T \ln{\rho \Lambda^3} \\ + = & k T \ln{\frac{\phi P \Lambda^3}{k T}} + + +where *k* is Boltzman's constant, *T* is the user-specified +temperature, :math:`\rho` is the number density, *P* is the pressure, +and :math:`\phi` is the fugacity coefficient. The constant +:math:`\Lambda` is required for dimensional consistency. For all unit +styles except *lj* it is defined as the thermal de Broglie wavelength + +.. math:: -where k is Boltzman's constant, -T is the user-specified temperature, rho is the number density, -P is the pressure, and phi is the fugacity coefficient. -The constant Lambda is required for dimensional consistency. -For all unit styles except *lj* it is defined as the thermal -de Broglie wavelength + \Lambda = \sqrt{ \frac{h^2}{2 \pi m k T}} -.. image:: Eqs/fix_gcmc3.jpg - :align: center -where h is Planck's constant, and m is the mass of the exchanged atom -or molecule. For unit style *lj*\ , Lambda is simply set to the -unity. Note that prior to March 2017, lambda for unit style *lj* was -calculated using the above formula with h set to the rather specific +where *h* is Planck's constant, and *m* is the mass of the exchanged atom +or molecule. For unit style *lj*\ , :math:`\Lambda` is simply set to +unity. Note that prior to March 2017, :math:`\Lambda` for unit style *lj* +was calculated using the above formula with *h* set to the rather specific value of 0.18292026. Chemical potential under the old definition can be converted to an equivalent value under the new definition by -subtracting 3kTln(Lambda\_old). +subtracting :math:`3 k T \ln(\Lambda_{old})`. As an alternative to specifying mu directly, the ideal gas reservoir -can be defined by its pressure P using the *pressure* keyword, in +can be defined by its pressure *P* using the *pressure* keyword, in which case the user-specified chemical potential is ignored. The user -may also specify the fugacity coefficient phi using the +may also specify the fugacity coefficient :math:`\phi` using the *fugacity\_coeff* keyword, which defaults to unity. The *full\_energy* option means that the fix calculates the total @@ -322,7 +328,7 @@ this will ensure roughly the same behavior whether or not the *full\_energy* option is used. Inserted atoms and molecules are assigned random velocities based on -the specified temperature T. Because the relative velocity of all +the specified temperature *T*. Because the relative velocity of all atoms in the molecule is zero, this may result in inserted molecules that are systematically too cold. In addition, the intramolecular potential energy of the inserted molecule may cause the kinetic energy diff --git a/doc/src/fix_gld.rst b/doc/src/fix_gld.rst index fdc1bd3c6a..8dc2b9dd98 100644 --- a/doc/src/fix_gld.rst +++ b/doc/src/fix_gld.rst @@ -62,8 +62,12 @@ to be a Prony series. With this fix active, the force on the *j*\ th atom is given as -.. image:: Eqs/fix_gld1.jpg - :align: center +.. math:: + + {\bf F}_{j}(t) = & {\bf F}^C_j(t)-\int \limits_{0}^{t} \Gamma_j(t-s) {\bf v}_j(s)~\text{d}s + {\bf F}^R_j(t) \\ + \Gamma_j(t-s) = & \sum \limits_{k=1}^{N_k} \frac{c_k}{\tau_k} e^{-(t-s)/\tau_k} \\ + \langle{\bf F}^R_j(t),{\bf F}^R_j(s)\rangle = & \text{k$_\text{B}$T} ~\Gamma_j(t-s) + Here, the first term is representative of all conservative (pairwise, bonded, etc) forces external to this fix, the second is the temporally @@ -72,7 +76,7 @@ the colored Gaussian random force. The Prony series form of the memory kernel is chosen to enable an extended variable formalism, with a number of exemplary mathematical -features discussed in :ref:`(Baczewski) `. In particular, 3N\_k +features discussed in :ref:`(Baczewski) `. In particular, :math:`3N_k` extended variables are added to each atom, which effect the action of the memory kernel without having to explicitly evaluate the integral over time in the second term of the force. This also has the benefit diff --git a/doc/src/fix_grem.rst b/doc/src/fix_grem.rst index 4c2054e0c0..53b815ec36 100644 --- a/doc/src/fix_grem.rst +++ b/doc/src/fix_grem.rst @@ -38,17 +38,19 @@ which uses non-Boltzmann ensembles to sample over first order phase transitions. The is done by defining replicas with an enthalpy dependent effective temperature -.. image:: Eqs/fix_grem.jpg - :align: center +.. math:: -with *eta* negative and steep enough to only intersect the + T_{eff} = \lambda + \eta (H - H_0) + + +with :math:`\eta` negative and steep enough to only intersect the characteristic microcanonical temperature (Ts) of the system once, -ensuring a unimodal enthalpy distribution in that replica. *Lambda* is -the intercept and effects the generalized ensemble similar to how -temperature effects a Boltzmann ensemble. *H0* is a reference -enthalpy, and is typically set as the lowest desired sampled enthalpy. -Further explanation can be found in our recent papers -:ref:`(Malolepsza) `. +ensuring a unimodal enthalpy distribution in that replica. +:math:`\lambda` is the intercept and effects the generalized ensemble +similar to how temperature effects a Boltzmann ensemble. :math:`H_0` +is a reference enthalpy, and is typically set as the lowest desired +sampled enthalpy. Further explanation can be found in our recent +papers :ref:`(Malolepsza) `. This fix requires a Nose-Hoover thermostat fix reference passed to the grem as *thermostat-ID*\ . Two distinct temperatures exist in this @@ -59,13 +61,13 @@ algorithms can be used. The fix enforces a generalized ensemble in a single replica only. Typically, this ideology is combined with replica exchange with -replicas differing by *lambda* only for simplicity, but this is not +replicas differing by :math:`\lambda` only for simplicity, but this is not required. A multi-replica simulation can be run within the LAMMPS environment using the :doc:`temper/grem ` command. This utilizes LAMMPS partition mode and requires the number of available processors be on the order of the number of desired replicas. A 100-replica simulation would require at least 100 processors (1 per -world at minimum). If a many replicas are needed on a small number of +world at minimum). If many replicas are needed on a small number of processors, multi-replica runs can be run outside of LAMMPS. An example of this can be found in examples/USER/misc/grem and has no limit on the number of replicas per processor. However, this is very @@ -74,13 +76,13 @@ inefficient and error prone and should be avoided if possible. In general, defining the generalized ensembles is unique for every system. When starting a many-replica simulation without any knowledge of the underlying microcanonical temperature, there are several tricks -we have utilized to optimize the process. Choosing a less-steep *eta* -yields broader distributions, requiring fewer replicas to map the -microcanonical temperature. While this likely struggles from the same -sampling problems gREM was built to avoid, it provides quick insight -to Ts. Initially using an evenly-spaced *lambda* distribution -identifies regions where small changes in enthalpy lead to large -temperature changes. Replicas are easily added where needed. +we have utilized to optimize the process. Choosing a less-steep +:math:`\eta` yields broader distributions, requiring fewer replicas to +map the microcanonical temperature. While this likely struggles from +the same sampling problems gREM was built to avoid, it provides quick +insight to Ts. Initially using an evenly-spaced :math:`\lambda` +distribution identifies regions where small changes in enthalpy lead +to large temperature changes. Replicas are easily added where needed. ---------- diff --git a/doc/src/fix_hyper_global.rst b/doc/src/fix_hyper_global.rst index 809bd37981..2d0cda5970 100644 --- a/doc/src/fix_hyper_global.rst +++ b/doc/src/fix_hyper_global.rst @@ -58,65 +58,67 @@ Fichthorn as described in :ref:`(Miron) `. In LAMMPS we use a simplified version of bond-boost GHD where a single bond in the system is biased at any one timestep. -Bonds are defined between each pair of I,J atoms whose R0ij distance -is less than *cutbond*\ , when the system is in a quenched state +Bonds are defined between each pair of atoms *ij*\ , whose :math:`R^0_{ij}` +distance is less than *cutbond*\ , when the system is in a quenched state (minimum) energy. Note that these are not "bonds" in a covalent sense. A bond is simply any pair of atoms that meet the distance criterion. *Cutbond* is an argument to this fix; it is discussed -below. A bond is only formed if one or both of the I.J atoms are in +below. A bond is only formed if one or both of the *ij* atoms are in the specified group. -The current strain of bond IJ (when running dynamics) is defined as +The current strain of bond *ij* (when running dynamics) is defined as -.. parsed-literal:: +.. math:: - Eij = (Rij - R0ij) / R0ij + E_{ij} = \frac{R_{ij} - R^0_{ij}}{R^0_{ij}} -where Rij is the current distance between atoms I,J, and R0ij is the -equilibrium distance in the quenched state. +where :math:`R_{ij}` is the current distance between atoms *i* and *j*\ , +and :math:`R^0_{ij}` is the equilibrium distance in the quenched state. -The bias energy Vij of any bond IJ is defined as +The bias energy :math:`V_{ij}` of any bond between atoms *i* and *j* +is defined as -.. parsed-literal:: +.. math:: - Vij = Vmax \* (1 - (Eij/q)\^2) for abs(Eij) < qfactor - = 0 otherwise + V_{ij} = V^{max} \cdot \left( 1 - \left(\frac{E_{ij}}{q}\right)^2 \right) \textrm{ for } \left|E_{ij}\right| < qfactor \textrm{ or } 0 \textrm{ otherwise} -where the prefactor *Vmax* and the cutoff *qfactor* are arguments to +where the prefactor :math:`V^{max}` and the cutoff *qfactor* are arguments to this fix; they are discussed below. This functional form is an -inverse parabola centered at 0.0 with height Vmax and which goes to -0.0 at +/- qfactor. +inverse parabola centered at 0.0 with height :math:`V^{max}` and +which goes to 0.0 at +/- qfactor. -Let Emax = the maximum of abs(Eij) for all IJ bonds in the system on a -given timestep. On that step, Vij is added as a bias potential to -only the single bond with strain Emax, call it Vij(max). Note that -Vij(max) will be 0.0 if Emax >= qfactor on that timestep. Also note -that Vij(max) is added to the normal interatomic potential that is -computed between all atoms in the system at every step. +Let :math:`E^{max}` be the maximum of :math:`\left| E_{ij} \right|` +for all *ij* bonds in the system on a +given timestep. On that step, :math:`V_{ij}` is added as a bias potential +to only the single bond with strain :math:`E^{max}`, call it +:math:`V^{max}_{ij}`. Note that :math:`V^{max}_{ij}` will be 0.0 +if :math:`E^{max} >= \textrm{qfactor}` on that timestep. Also note +that :math:`V^{max}_{ij}` is added to the normal interatomic potential +that is computed between all atoms in the system at every step. -The derivative of Vij(max) with respect to the position of each atom -in the Emax bond gives a bias force Fij(max) acting on the bond as +The derivative of :math:`V^{max}_{ij}` with respect to the position of +each atom in the :math:`E^{max}` bond gives a bias force +:math:`F^{max}_{ij}` acting on the bond as -.. parsed-literal:: +.. math:: - Fij(max) = - dVij(max)/dEij = 2 Vmax Eij / qfactor\^2 for abs(Eij) < qfactor - = 0 otherwise + F^{max}_{ij} = - \frac{dV^{max}_{ij}}{dE_{ij}} = \frac{2 V^{max} E-{ij}}{\textrm{qfactor}^2} \textrm{ for } \left|E_{ij}\right| < \textrm{qfactor} \textrm{ or } 0 \textrm{ otherwise} which can be decomposed into an equal and opposite force acting on -only the two I,J atoms in the Emax bond. +only the two *ij* atoms in the :math:`E^{max}` bond. The time boost factor for the system is given each timestep I by -.. parsed-literal:: +.. math:: - Bi = exp(beta \* Vij(max)) + B_i = e^{\beta V^{max}_{ij}} -where beta = 1/kTequil, and *Tequil* is the temperature of the system -and an argument to this fix. Note that Bi >= 1 at every step. +where :math:`\beta = \frac{1}{kT_{equil}}`, and :math:`T_{equil}` is the temperature of the system +and an argument to this fix. Note that :math:`B_i >= 1` at every step. .. note:: @@ -125,21 +127,21 @@ and an argument to this fix. Note that Bi >= 1 at every step. constant-temperature (NVT) dynamics. LAMMPS does not check that this is done. -The elapsed time t\_hyper for a GHD simulation running for *N* +The elapsed time :math:`t_{hyper}` for a GHD simulation running for *N* timesteps is simply -.. parsed-literal:: +.. math:: - t_hyper = Sum (i = 1 to N) Bi \* dt + t_{hyper} = \sum_{i=1,N} B-i \cdot dt -where dt is the timestep size defined by the :doc:`timestep ` +where *dt* is the timestep size defined by the :doc:`timestep ` command. The effective time acceleration due to GHD is thus t\_hyper / N\*dt, where N\*dt is elapsed time for a normal MD run of N timesteps. Note that in GHD, the boost factor varies from timestep to timestep. -Likewise, which bond has Emax strain and thus which pair of atoms the -bias potential is added to, will also vary from timestep to timestep. +Likewise, which bond has :math:`E^{max}` strain and thus which pair of +atoms the bias potential is added to, will also vary from timestep to timestep. This is in contrast to local hyperdynamics (LHD) where the boost factor is an input parameter; see the :doc:`fix hyper/local ` doc page for details. @@ -150,9 +152,9 @@ factor is an input parameter; see the :doc:`fix hyper/local ` d Here is additional information on the input parameters for GHD. The *cutbond* argument is the cutoff distance for defining bonds -between pairs of nearby atoms. A pair of I,J atoms in their +between pairs of nearby atoms. A pair of *ij* atoms in their equilibrium, minimum-energy configuration, which are separated by a -distance Rij < *cutbond*\ , are flagged as a bonded pair. Setting +distance :math:`R_{ij} < cutbond`, are flagged as a bonded pair. Setting *cubond* to be ~25% larger than the nearest-neighbor distance in a crystalline lattice is a typical choice for solids, so that bonds exist only between nearest neighbor pairs. @@ -166,7 +168,7 @@ could still experience a non-zero bias force. If *qfactor* is set too large, then transitions from one energy basin to another are affected because the bias potential is non-zero at the transition state (e.g. saddle point). If *qfactor* is set too small -than little boost is achieved because the Eij strain of some bond in +than little boost is achieved because the :math:`E_{ij}` strain of some bond in the system will (nearly) always exceed *qfactor*\ . A value of 0.3 for *qfactor* is typically reasonable. @@ -220,7 +222,7 @@ scalar is the magnitude of the bias potential (energy units) applied on the current timestep. The vector stores the following quantities: * 1 = boost factor on this step (unitless) -* 2 = max strain Eij of any bond on this step (absolute value, unitless) +* 2 = max strain :math:`E_{ij}` of any bond on this step (absolute value, unitless) * 3 = ID of first atom in the max-strain bond * 4 = ID of second atom in the max-strain bond * 5 = average # of bonds/atom on this step diff --git a/doc/src/fix_hyper_local.rst b/doc/src/fix_hyper_local.rst index 335cd10f69..d7d0f012b6 100644 --- a/doc/src/fix_hyper_local.rst +++ b/doc/src/fix_hyper_local.rst @@ -77,66 +77,66 @@ To understand this description, you should first read the description of the GHD algorithm on the :doc:`fix hyper/global ` doc page. This description of LHD builds on the GHD description. -The definition of bonds and Eij are the same for GHD and LHD. The -formulas for Vij(max) and Fij(max) are also the same except for a -pre-factor Cij, explained below. +The definition of bonds and :math:`E_{ij}` are the same for GHD and LHD. +The formulas for :math:`V^{max}_{ij}` and :math:`F^{max}_{ij}` are also +the same except for a pre-factor :math:`C_{ij}`, explained below. -The bias energy Vij applied to a bond IJ with maximum strain is +The bias energy :math:`V_{ij}` applied to a bond *ij* with maximum strain is -.. parsed-literal:: +.. math:: - Vij(max) = Cij \* Vmax \* (1 - (Eij/q)\^2) for abs(Eij) < qfactor - = 0 otherwise + V^{max}_{ij} = C_{ij} \cdot V^{max} \cdot \left(1 - \left(\frac{E_{ij}}{q}\right)^2\right) \textrm{ for } \left|E_{ij}\right| < qfactor \textrm{ or } 0 \textrm{ otherwise} -The derivative of Vij(max) with respect to the position of each atom -in the IJ bond gives a bias force Fij(max) acting on the bond as +The derivative of :math:`V^{max}_{ij}` with respect to the position of +each atom in the *ij* bond gives a bias force :math:`F^{max}_{ij}` acting +on the bond as -.. parsed-literal:: +.. math:: - Fij(max) = - dVij(max)/dEij = 2 Cij Vmax Eij / qfactor\^2 for abs(Eij) < qfactor - = 0 otherwise + F^{max}_{ij} = - \frac{dV^{max}_{ij}}{dE_{ij}} = 2 C_{ij} V^{max} \frac{E_{ij}}{qfactor^2} \textrm{ for } \left|E_{ij}\right| < qfactor \textrm{ or } 0 \textrm{ otherwise} which can be decomposed into an equal and opposite force acting on -only the two I,J atoms in the IJ bond. +only the two atoms *i* and *j* in the *ij* bond. The key difference is that in GHD a bias energy and force is added (on a particular timestep) to only one bond (pair of atoms) in the system, -which is the bond with maximum strain Emax. +which is the bond with maximum strain :math:`E^{max}`. In LHD, a bias energy and force can be added to multiple bonds -separated by the specified *Dcut* distance or more. A bond IJ is +separated by the specified *Dcut* distance or more. A bond *ij* is biased if it is the maximum strain bond within its local -"neighborhood", which is defined as the bond IJ plus any neighbor -bonds within a distance *Dcut* from IJ. The "distance" between bond -IJ and bond KL is the minimum distance between any of the IK, IL, JK, -JL pairs of atoms. +"neighborhood", which is defined as the bond *ij* plus any neighbor +bonds within a distance *Dcut* from *ij*. The "distance" between bond +*ij* and bond *kl* is the minimum distance between any of the *ik*, *il*, +*jk*, and *jl* pairs of atoms. For a large system, multiple bonds will typically meet this -requirement, and thus a bias potential Vij(max) will be applied to -many bonds on the same timestep. +requirement, and thus a bias potential :math:`V^{max}_{ij}` will be +applied to many bonds on the same timestep. -In LHD, all bonds store a Cij prefactor which appears in the Vij(max) -and Fij(max) equations above. Note that the Cij factor scales the -strength of the bias energy and forces whenever bond IJ is the maximum -strain bond in its neighborhood. +In LHD, all bonds store a :math:`C_{ij}` prefactor which appears in +the :math:`V^{max}_{ij}` and :math:`F^{max}_{ij}equations above. Note +that the :math:`C_{ij}` factor scales the strength of the bias energy +and forces whenever bond *ij* is the maximum strain bond in its neighborhood. -Cij is initialized to 1.0 when a bond between the I,J atoms is first -defined. The specified *Btarget* factor is then used to adjust the -Cij prefactors for each bond every timestep in the following manner. +:math:`C_{ij}` is initialized to 1.0 when a bond between the *ij* atoms +is first defined. The specified *Btarget* factor is then used to adjust the +:math:`C_{ij}` prefactors for each bond every timestep in the following manner. -An instantaneous boost factor Bij is computed each timestep +An instantaneous boost factor :math:`B_{ij}` is computed each timestep for each bond, as -.. parsed-literal:: +.. math:: - Bij = exp(beta \* Vkl(max)) + B_{ij} = e^{\beta V^{max}_{kl}} -where Vkl(max) is the bias energy of the maxstrain bond KL within bond -IJ's neighborhood, beta = 1/kTequil, and *Tequil* is the temperature -of the system and an argument to this fix. +where :math:`V^{max}_{kl}` is the bias energy of the maxstrain bond *kl* +within bond *ij*\ 's neighborhood, :math:`\beta = \frac{1}{kT_{equil}}`, +and :math:`T_{equil}` is the temperature of the system and an argument +to this fix. .. note:: @@ -146,28 +146,32 @@ of the system and an argument to this fix. running constant-temperature (NVT) dynamics. LAMMPS does not check that this is done. -Note that if IJ = KL, then bond IJ is a biased bond on that timestep, -otherwise it is not. But regardless, the boost factor Bij can be -thought of an estimate of time boost currently being applied within a -local region centered on bond IJ. For LHD, we want this to be the -specified *Btarget* value everywhere in the simulation domain. - -To accomplish this, if Bij < Btarget, the Cij prefactor for bond IJ is -incremented on the current timestep by an amount proportional to the -inverse of the specified *alpha* and the difference (Bij - Btarget). -Conversely if Bij > Btarget, Cij is decremented by the same amount. -This procedure is termed "boostostatting" in -:ref:`(Voter2013) `. It drives all of the individual Cij to -values such that when Vij\ *max* is applied as a bias to bond IJ, the -resulting boost factor Bij will be close to *Btarget* on average. +Note that if *ij*\ == *kl*\ , then bond *ij* is a biased bond on that +timestep, otherwise it is not. But regardless, the boost factor +:math:`B_{ij}` can be thought of an estimate of time boost currently +being applied within a local region centered on bond *ij*. For LHD, +we want this to be the specified *Btarget* value everywhere in the +simulation domain. + +To accomplish this, if :math:`B_{ij} < B_{target}`, the :math:`C_{ij}` +prefactor for bond *ij* is incremented on the current timestep by an +amount proportional to the inverse of the specified *alpha* and the +difference (:math:`B_{ij} - B_{target}`). +Conversely if :math:`B_{ij} > B_{target}`, :math:`C_{ij}` is decremented +by the same amount. +This procedure is termed "boostostatting" in :ref:`(Voter2013) `. +It drives all of the individual :math:`C_{ij}` to +values such that when :math:`V^{max}_{ij}` is applied as a bias to +bond *ij*, the resulting boost factor :math:`B_{ij}` will be close +to :math:`B_{target}` on average. Thus the LHD time acceleration factor for the overall system is effectively *Btarget*\ . -Note that in LHD, the boost factor *Btarget* is specified by the user. +Note that in LHD, the boost factor :math:`B_{target}` is specified by the user. This is in contrast to global hyperdynamics (GHD) where the boost -factor varies each timestep and is computed as a function of *Vmax*\ , -Emax, and *Tequil*\ ; see the :doc:`fix hyper/global ` -doc page for details. +factor varies each timestep and is computed as a function of :math:`V_{max}`, +:math:`E_{max}`, and :math:`T_{equil}`; see the +:doc:`fix hyper/global ` doc page for details. ---------- @@ -182,7 +186,7 @@ The *Dcut*\ , *alpha*\ , and *Btarget* parameters are unique to LHD. The *cutbond* argument is the cutoff distance for defining bonds between pairs of nearby atoms. A pair of I,J atoms in their equilibrium, minimum-energy configuration, which are separated by a -distance Rij < *cutbond*\ , are flagged as a bonded pair. Setting +distance :math:`R_{ij} < cutbond`, are flagged as a bonded pair. Setting *cubond* to be ~25% larger than the nearest-neighbor distance in a crystalline lattice is a typical choice for solids, so that bonds exist only between nearest neighbor pairs. @@ -190,37 +194,40 @@ exist only between nearest neighbor pairs. The *qfactor* argument is the limiting strain at which the bias potential goes to 0.0. It is dimensionless, so a value of 0.3 means a bond distance can be up to 30% larger or 30% smaller than the -equilibrium (quenched) R0ij distance and the two atoms in the bond +equilibrium (quenched) :math:`R^0_{ij}` distance and the two atoms in the bond could still experience a non-zero bias force. If *qfactor* is set too large, then transitions from one energy basin to another are affected because the bias potential is non-zero at the transition state (e.g. saddle point). If *qfactor* is set too small -than little boost can be achieved because the Eij strain of some bond in +than little boost can be achieved because the :math:`E_{ij}` strain of +some bond in the system will (nearly) always exceed *qfactor*\ . A value of 0.3 for *qfactor* is typically a reasonable value. The *Vmax* argument is a fixed prefactor on the bias potential. There -is a also a dynamic prefactor Cij, driven by the choice of *Btarget* -as discussed above. The product of these should be a value less than +is a also a dynamic prefactor :math:`C_{ij}`, driven by the choice of +*Btarget* as discussed above. The product of these should be a value less than the smallest barrier height for an event to occur. Otherwise the applied bias potential may be large enough (when added to the interatomic potential) to produce a local energy basin with a maxima in the center. This can produce artificial energy minima in the same -basin that trap an atom. Or if Cij\*\ *Vmax* is even larger, it may +basin that trap an atom. Or if :math:`C_{ij} \cdot V^{max}` is even +larger, it may induce an atom(s) to rapidly transition to another energy basin. Both cases are "bad dynamics" which violate the assumptions of LHD that guarantee an accelerated time-accurate trajectory of the system. .. note:: - It may seem that *Vmax* can be set to any value, and Cij will - compensate to reduce the overall prefactor if necessary. However the - Cij are initialized to 1.0 and the boostostatting procedure typically - operates slowly enough that there can be a time period of bad dynamics - if *Vmax* is set too large. A better strategy is to set *Vmax* to the + It may seem that :math:`V^{max}` can be set to any value, and + :math:`C_{ij}` will compensate to reduce the overall prefactor + if necessary. However the :math:`C_{ij}` are initialized to 1.0 + and the boostostatting procedure typically operates slowly enough + that there can be a time period of bad dynamics if :math:`V^{max}` + is set too large. A better strategy is to set :math:`V^{max}` to the slightly smaller than the lowest barrier height for an event (the same - as for GHD), so that the Cij remain near unity. + as for GHD), so that the :math:`C_{ij}` remain near unity. The *Tequil* argument is the temperature at which the system is simulated; see the comment above about the :doc:`fix langevin ` thermostatting. It is also part of the @@ -262,11 +269,11 @@ half the *cutbond* parameter as an estimate to warn if the ghost cutoff is not long enough. As described above the *alpha* argument is a pre-factor in the -boostostat update equation for each bond's Cij prefactor. *Alpha* is -specified in time units, similar to other thermostat or barostat +boostostat update equation for each bond's :math:`C_{ij}` prefactor. +*Alpha* is specified in time units, similar to other thermostat or barostat damping parameters. It is roughly the physical time it will take the -boostostat to adjust a Cij value from a too high (or too low) value to -a correct one. An *alpha* setting of a few ps is typically good for +boostostat to adjust a :math:`C_{ij}` value from a too high (or too low) +value to a correct one. An *alpha* setting of a few ps is typically good for solid-state systems. Note that the *alpha* argument here is the inverse of the alpha parameter discussed in :ref:`(Voter2013) `. @@ -276,25 +283,26 @@ that all the atoms in the system will experience. The elapsed time t\_hyper for an LHD simulation running for *N* timesteps is simply -.. parsed-literal:: +.. math:: - t_hyper = Btarget \* N\*dt + t_{hyper} = B_{target} \cdot N \cdot dt -where dt is the timestep size defined by the :doc:`timestep ` -command. The effective time acceleration due to LHD is thus t\_hyper / -N\*dt = Btarget, where N\*dt is elapsed time for a normal MD run -of N timesteps. +where *dt* is the timestep size defined by the :doc:`timestep ` +command. The effective time acceleration due to LHD is thus +:math:`\frac{t_{hyper}}{N\cdot dt} = B_{target}`, where :math:`N\cdot dt` +is the elapsed time for a normal MD run of N timesteps. You cannot choose an arbitrarily large setting for *Btarget*\ . The maximum value you should choose is -.. parsed-literal:: +.. math:: - Btarget = exp(beta \* Vsmall) + B_{target} = e^{\beta V_{small}} -where Vsmall is the smallest event barrier height in your system, beta -= 1/kTequil, and *Tequil* is the specified temperature of the system +where :math:`V_{small}` is the smallest event barrier height in your +system, :math:`\beta = \frac{1}{kT_{equil}}`, and :math:`T_{equil}` +is the specified temperature of the system (both by this fix and the Langevin thermostat). Note that if *Btarget* is set smaller than this, the LHD simulation @@ -315,41 +323,42 @@ time (t\_hyper equation above) will be shorter. Here is additional information on the optional keywords for this fix. -The *bound* keyword turns on min/max bounds for bias coefficients Cij -for all bonds. Cij is a prefactor for each bond on the bias potential -of maximum strength Vmax. Depending on the choice of *alpha* and -*Btarget* and *Vmax*\ , the boostostatting can cause individual Cij -values to fluctuate. If the fluctuations are too large Cij\*Vmax can -exceed low barrier heights and induce bad event dynamics. Bounding -the Cij values is a way to prevent this. If *Bfrac* is set to -1 or -any negative value (the default) then no bounds are enforced on Cij -values (except they must always be >= 0.0). A *Bfrac* setting >= 0.0 -sets a lower bound of 1.0 - Bfrac and upper bound of 1.0 + Bfrac on -each Cij value. Note that all Cij values are initialized to 1.0 when -a bond is created for the first time. Thus *Bfrac* limits the bias -potential height to *Vmax* +/- *Bfrac*\ \*\ *Vmax*\ . - -The *reset* keyword allow *Vmax* to be adjusted dynamically depending -on the average value of all Cij prefactors. This can be useful if you +The *bound* keyword turns on min/max bounds for bias coefficients +:math:`C_{ij}` for all bonds. :math:`C_{ij}` is a prefactor for each bond on +the bias potential of maximum strength :math:`V^{max}`. Depending on the +choice of *alpha* and *Btarget* and *Vmax*\ , the boostostatting can cause +individual :math:`C_{ij}` values to fluctuate. If the fluctuations are too +large :math:`C_{ij} \cdot V^{max}` can exceed low barrier heights and induce +bad event dynamics. Bounding the :math:`C_{ij}` values is a way to prevent +this. If *Bfrac* is set to -1 or any negative value (the default) then no +bounds are enforced on :math:`C_{ij}` values (except they must always +be >= 0.0). A *Bfrac* setting >= 0.0 +sets a lower bound of 1.0 - Bfrac and upper bound of 1.0 + Bfrac on each +:math:`C_{ij}` value. Note that all :math:`C_{ij}` values are initialized +to 1.0 when a bond is created for the first time. Thus *Bfrac* limits the +bias potential height to *Vmax* +/- *Bfrac*\ \*\ *Vmax*\ . + +The *reset* keyword allow *Vmax* to be adjusted dynamically depending on the +average value of all :math:`C_{ij}` prefactors. This can be useful if you are unsure what value of *Vmax* will match the *Btarget* boost for the -system. The Cij values will then adjust in aggregate (up or down) so -that Cij\*Vmax produces a boost of *Btarget*\ , but this may conflict -with the *bound* keyword settings. By using *bound* and *reset* -together, *Vmax* itself can be reset, and desired bounds still applied -to the Cij values. +system. The :math:`C_{ij}` values will then adjust in aggregate (up or down) +so that :math:`C_{ij} \cdot V^{max}` produces a boost of *Btarget*\ , but this +may conflict with the *bound* keyword settings. By using *bound* and *reset* +together, :math:`V^{max}` itself can be reset, and desired bounds still applied +to the :math:`C_{ij}` values. A setting for *Rfreq* of -1 (the default) means *Vmax* never changes. -A setting of 0 means *Vmax* is adjusted every time an event occurs and +A setting of 0 means :math:`V^{max}` is adjusted every time an event occurs and bond pairs are recalculated. A setting of N > 0 timesteps means -*Vmax* is adjusted on the first time an event occurs on a timestep >= -N steps after the previous adjustment. The adjustment to *Vmax* is -computed as follows. The current average of all Cij\*Vmax values is -computed and the *Vmax* is reset to that value. All Cij values are -changed to new prefactors such the new Cij\*Vmax is the same as it was -previously. If the *bound* keyword was used, those bounds are -enforced on the new Cij values. Henceforth, new bonds are assigned a -Cij = 1.0, which means their bias potential magnitude is the new -*Vmax*\ . +:math:`V^{max}` is adjusted on the first time an event occurs on a timestep >= +N steps after the previous adjustment. The adjustment to :math:`V^{max}` is +computed as follows. The current average of all :math:`C_{ij} \cdot V^{max}` +values is computed and the :math:`V^{max}` is reset to that value. All +:math:`C_{ij}` values are changed to new prefactors such the new +:math:`C_{ij} \cdot V^{max}` is the same as it was previously. If the +*bound* keyword was used, those bounds are enforced on the new :math:`C_{ij}` +values. Henceforth, new bonds are assigned a :math:`C_{ij} = 1.0`, which +means their bias potential magnitude is the new :math:`V^{max}`. The *check/ghost* keyword turns on extra computation each timestep to compute statistics about ghost atoms used to determine which bonds to @@ -390,8 +399,8 @@ vector stores the following quantities: * 1 = average boost for all bonds on this step (unitless) * 2 = # of biased bonds on this step -* 3 = max strain Eij of any bond on this step (absolute value, unitless) -* 4 = value of Vmax on this step (energy units) +* 3 = max strain :math:`E_{ij}` of any bond on this step (absolute value, unitless) +* 4 = value of :math:`V^{max}` on this step (energy units) * 5 = average bias coeff for all bonds on this step (unitless) * 6 = min bias coeff for all bonds on this step (unitless) * 7 = max bias coeff for all bonds on this step (unitless) @@ -428,12 +437,12 @@ multiple runs (since the point in the input script the fix was defined). For value 10, each bond instantaneous boost factor is given by the -equation for Bij above. The total system boost (average across all +equation for :math:`B_{ij}` above. The total system boost (average across all bonds) fluctuates, but should average to a value close to the -specified Btarget. +specified :math:`B_{target}`. For value 12, the numerator is a count of all biased bonds on each -timestep whose bias energy = 0.0 due to Eij >= *qfactor*\ . The +timestep whose bias energy = 0.0 due to :math:`E_{ij} >= qfactor`. The denominator is the count of all biased bonds on all timesteps. For value 13, the numerator is a count of all biased bonds on each @@ -522,12 +531,12 @@ The scalar and vector values calculated by this fix are all "intensive". This fix also computes a local vector of length the number of bonds -currently in the system. The value for each bond is its Cij prefactor -(bias coefficient). These values can be can be accessed by various +currently in the system. The value for each bond is its :math:`C_{ij}` +prefactor (bias coefficient). These values can be can be accessed by various :doc:`output commands `. A particularly useful one is the :doc:`fix ave/histo ` command which can be used to histogram the Cij values to see if they are distributed reasonably -close to 1.0, which indicates a good choice of *Vmax*\ . +close to 1.0, which indicates a good choice of :math:`V^{max}`. The local values calculated by this fix are unitless. diff --git a/doc/src/fix_langevin_spin.rst b/doc/src/fix_langevin_spin.rst index bccedc8520..b229a2ae8d 100644 --- a/doc/src/fix_langevin_spin.rst +++ b/doc/src/fix_langevin_spin.rst @@ -36,16 +36,19 @@ Brownian dynamics (BD). A random torque and a transverse dissipation are applied to each spin i according to the following stochastic differential equation: -.. image:: Eqs/fix_langevin_spin_sLLG.jpg - :align: center +.. math:: -with lambda the transverse damping, and eta a random vector. + \frac{d \vec{s}_{i}}{dt} = \frac{1}{\left(1+\lambda^2 \right)} \left( \left( + \vec{\omega}_{i} +\vec{\eta} \right) \times \vec{s}_{i} + \lambda\, \vec{s}_{i} + \times\left( \vec{\omega}_{i} \times\vec{s}_{i} \right) \right) + +with :math:`\lambda` the transverse damping, and :math:`\eta` a random vector. This equation is referred to as the stochastic Landau-Lifshitz-Gilbert (sLLG) equation. -The components of eta are drawn from a Gaussian probability law. Their amplitude -is defined as a proportion of the temperature of the external thermostat T (in K -in metal units). +The components of :math:`\eta` are drawn from a Gaussian probability +law. Their amplitude is defined as a proportion of the temperature of +the external thermostat T (in K in metal units). More details about this implementation are reported in :ref:`(Tranchida) `. diff --git a/doc/src/fix_lb_fluid.rst b/doc/src/fix_lb_fluid.rst index b7ce7ffdc8..0c923d923b 100644 --- a/doc/src/fix_lb_fluid.rst +++ b/doc/src/fix_lb_fluid.rst @@ -69,33 +69,42 @@ dependent force to the fluid. The lattice-Boltzmann algorithm solves for the fluid motion governed by the Navier Stokes equations, -.. image:: Eqs/fix_lb_fluid_navierstokes.jpg - :align: center +.. math:: + + \partial_t \rho + \partial_{\beta}\left(\rho u_{\beta}\right)= & 0 \\ + \partial_t\left(\rho u_{\alpha}\right) + \partial_{\beta}\left(\rho u_{\alpha} u_{\beta}\right) = & \partial_{\beta}\sigma_{\alpha \beta} + F_{\alpha} + \partial_{\beta}\left(\eta_{\alpha \beta \gamma \nu}\partial_{\gamma} u_{\nu}\right) + with, -.. image:: Eqs/fix_lb_fluid_viscosity.jpg - :align: center +.. math:: + + \eta_{\alpha \beta \gamma \nu} = \eta\left[\delta_{\alpha \gamma}\delta_{\beta \nu} + \delta_{\alpha \nu}\delta_{\beta \gamma} - \frac{2}{3}\delta_{\alpha \beta}\delta_{\gamma \nu}\right] + \Lambda \delta_{\alpha \beta}\delta_{\gamma \nu} + + +where :math:`\rho` is the fluid density, *u* is the local +fluid velocity, :math:`\sigma` is the stress tensor, *F* is a local external +force, and :math:`\eta` and :math:`\Lambda` are the shear and bulk viscosities +respectively. Here, we have implemented -where rho is the fluid density, u is the local fluid velocity, sigma -is the stress tensor, F is a local external force, and eta and Lambda -are the shear and bulk viscosities respectively. Here, we have -implemented +.. math:: -.. image:: Eqs/fix_lb_fluid_stress.jpg - :align: center + \sigma_{\alpha \beta} = -P_{\alpha \beta} = -\rho a_0 \delta_{\alpha \beta} -with a\_0 set to 1/3 (dx/dt)\^2 by default. + +with :math:`a_0` set to :math:`\frac{1}{3} \frac{dx}{dt}^2` by default. The algorithm involves tracking the time evolution of a set of partial distribution functions which evolve according to a velocity discretized version of the Boltzmann equation, -.. image:: Eqs/fix_lb_fluid_boltzmann.jpg - :align: center +.. math:: + + \left(\partial_t + e_{i\alpha}\partial_{\alpha}\right)f_i = -\frac{1}{\tau}\left(f_i - f_i^{eq}\right) + W_i + where the first term on the right hand side represents a single time -relaxation towards the equilibrium distribution function, and tau is a +relaxation towards the equilibrium distribution function, and :math:`\tau` is a parameter physically related to the viscosity. On a technical note, we have implemented a 15 velocity model (D3Q15) as default; however, the user can switch to a 19 velocity model (D3Q19) through the use of @@ -108,8 +117,10 @@ finite difference LB integrator is used. If *LBtype* is set equal to Physical variables are then defined in terms of moments of the distribution functions, -.. image:: Eqs/fix_lb_fluid_properties.jpg - :align: center +.. math:: + + \rho = & \displaystyle\sum\limits_{i} f_i \\ + \rho u_{\alpha} = & \displaystyle\sum\limits_{i} f_i e_{i\alpha} Full details of the lattice-Boltzmann algorithm used can be found in :ref:`Mackay et al. `. @@ -119,12 +130,15 @@ through a velocity dependent force. The contribution to the fluid force on a given lattice mesh site j due to MD particle alpha is calculated as: -.. image:: Eqs/fix_lb_fluid_fluidforce.jpg - :align: center +.. math:: + + {\bf F}_{j \alpha} = \gamma \left({\bf v}_n - {\bf u}_f \right) \zeta_{j\alpha} -where v\_n is the velocity of the MD particle, u\_f is the fluid + +where :math:`\mathbf{v}_n` is the velocity of the MD particle, +:math:`\mathbf{u}_f` is the fluid velocity interpolated to the particle location, and gamma is the force -coupling constant. Zeta is a weight assigned to the grid point, +coupling constant. :math:`\zeta` is a weight assigned to the grid point, obtained by distributing the particle to the nearest lattice sites. For this, the user has the choice between a trilinear stencil, which provides a support of 8 lattice sites, or the immersed boundary method @@ -135,20 +149,25 @@ to walls, due to its smaller support. Therefore, by default, the Peskin stencil is used; however the user may switch to the trilinear stencil by specifying the keyword, *trilinear*\ . -By default, the force coupling constant, gamma, is calculated according to +By default, the force coupling constant, :math:`\gamma`, is calculated +according to + +.. math:: -.. image:: Eqs/fix_lb_fluid_gammadefault.jpg - :align: center + \gamma = \frac{2m_um_v}{m_u+m_v}\left(\frac{1}{\Delta t_{collision}}\right) -Here, m\_v is the mass of the MD particle, m\_u is a representative -fluid mass at the particle location, and dt\_collision is a collision -time, chosen such that tau/dt\_collision = 1 (see :ref:`Mackay and Denniston ` for full details). In order to calculate m\_u, the -fluid density is interpolated to the MD particle location, and -multiplied by a volume, node\_area\*dx\_lb, where node\_area represents -the portion of the surface area of the composite object associated -with a given MD particle. By default, node\_area is set equal to -dx\_lb\*dx\_lb; however specific values for given atom types can be set -using the *setArea* keyword. + +Here, :math:`m_v` is the mass of the MD particle, :math:`m_u` is a +representative fluid mass at the particle location, and :math:`\Delta +t_{collision}` is a collision time, chosen such that +:math:`\frac{\tau}{\Delta t_{collision}} = 1` (see :ref:`Mackay and +Denniston ` for full details). In order to calculate :math:`m_u`, +the fluid density is interpolated to the MD particle location, and +multiplied by a volume, node\_area\*dx\_lb, where node\_area +represents the portion of the surface area of the composite object +associated with a given MD particle. By default, node\_area is set +equal to dx\_lb\*dx\_lb; however specific values for given atom types +can be set using the *setArea* keyword. The user also has the option of specifying their own value for the force coupling constant, for all the MD particles associated with the @@ -364,8 +383,10 @@ Default By default, the force coupling constant is set according to -.. image:: Eqs/fix_lb_fluid_gammadefault.jpg - :align: center +.. math:: + + \gamma = \frac{2m_um_v}{m_u+m_v}\left(\frac{1}{\Delta t_{collision}}\right) + and an area of dx\_lb\^2 per node, used to calculate the fluid mass at the particle node location, is assumed. diff --git a/doc/src/fix_mvv_dpd.rst b/doc/src/fix_mvv_dpd.rst index 55066c8ce4..211642e7ec 100644 --- a/doc/src/fix_mvv_dpd.rst +++ b/doc/src/fix_mvv_dpd.rst @@ -50,10 +50,14 @@ The modified velocity-Verlet (MVV) algorithm aims to improve the stability of the time integrator by using an extrapolated version of the velocity for the force evaluation: -.. image:: Eqs/fix_mvv_dpd.jpg - :align: center +.. math:: -where the parameter λ depends on the + v(t+\frac{\Delta t}{2}) = & v(t) + \frac{\Delta t}{2}\cdot a(t) \\ + r(t+\Delta t) = & r(t) + \Delta t\cdot v(t+\frac{\Delta t}{2}) \\ + a(t+\Delta t) = & \frac{1}{m}\cdot F\left[ r(t+\Delta t), v(t) +\lambda \cdot \Delta t\cdot a(t)\right] \\ + v(t+\Delta t) = & v(t+\frac{\Delta t}{2}) + \frac{\Delta t}{2}\cdot a(t+\Delta t) + +where the parameter :math:`\lambda` depends on the specific choice of DPD parameters, and needs to be tuned on a case-by-case basis. Specification of a *lambda* value is optional. If specified, the setting must be from 0.0 to 1.0. If not specified, diff --git a/doc/src/fix_nh.rst b/doc/src/fix_nh.rst index 36f2d6c8f3..88ece95e95 100644 --- a/doc/src/fix_nh.rst +++ b/doc/src/fix_nh.rst @@ -511,9 +511,28 @@ with *respa*\ , LAMMPS uses an integrator constructed according to the following factorization of the Liouville propagator (for two rRESPA levels): -.. image:: Eqs/fix_nh1.jpg - :align: center - +.. math:: + + \exp \left(\mathrm{i} L \Delta t \right) = & \hat{E} + \exp \left(\mathrm{i} L_{\rm T\textrm{-}baro} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\rm T\textrm{-}part} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\epsilon , 2} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{2}^{(2)} \frac{\Delta t}{2} \right) \\ + &\times \left[ + \exp \left(\mathrm{i} L_{2}^{(1)} \frac{\Delta t}{2n} \right) + \exp \left(\mathrm{i} L_{\epsilon , 1} \frac{\Delta t}{2n} \right) + \exp \left(\mathrm{i} L_1 \frac{\Delta t}{n} \right) + \exp \left(\mathrm{i} L_{\epsilon , 1} \frac{\Delta t}{2n} \right) + \exp \left(\mathrm{i} L_{2}^{(1)} \frac{\Delta t}{2n} \right) + \right]^n \\ + &\times + \exp \left(\mathrm{i} L_{2}^{(2)} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\epsilon , 2} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\rm T\textrm{-}part} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\rm T\textrm{-}baro} \frac{\Delta t}{2} \right) \\ + &+ \mathcal{O} \left(\Delta t^3 \right) + + This factorization differs somewhat from that of Tuckerman et al, in that the barostat is only updated at the outermost rRESPA level, whereas Tuckerman's factorization requires splitting the pressure into diff --git a/doc/src/fix_nphug.rst b/doc/src/fix_nphug.rst index 2261600f93..1d946e5f83 100644 --- a/doc/src/fix_nphug.rst +++ b/doc/src/fix_nphug.rst @@ -88,21 +88,23 @@ Essentially, a Hugoniostat simulation is an NPT simulation in which the user-specified target temperature is replaced with a time-dependent target temperature Tt obtained from the following equation: -.. image:: Eqs/fix_nphug.jpg - :align: center +.. math:: -where T and Tt are the instantaneous and target temperatures, -P and P0 are the instantaneous and reference pressures or axial stresses, + T_t - T = \frac{\left(\frac{1}{2}\left(P + P_0\right)\left(V_0 - V\right) + E_0 - E\right)}{N_{dof} k_B } = \Delta + + +where *T* and :math:`T_t` are the instantaneous and target temperatures, +*P* and :math:`P_0` are the instantaneous and reference pressures or axial stresses, depending on whether hydrostatic or uniaxial compression is being -performed, V and V0 are the instantaneous and reference volumes, -E and E0 are the instantaneous and reference internal energy (potential -plus kinetic), Ndof is the number of degrees of freedom used in the -definition of temperature, and kB is the Boltzmann constant. Delta is the +performed, *V* and :math:`V_0` are the instantaneous and reference volumes, +*E* and :math:`E_0` are the instantaneous and reference internal energy (potential +plus kinetic), :math:`N_{dof}` is the number of degrees of freedom used in the +definition of temperature, and :math:`k_B` is the Boltzmann constant. :math:`\Delta` is the negative deviation of the instantaneous temperature from the target temperature. -When the system reaches a stable equilibrium, the value of Delta should +When the system reaches a stable equilibrium, the value of :math:`\Delta` should fluctuate about zero. -The values of E0, V0, and P0 are the instantaneous values at the start of +The values of :math:`E_0`, :math:`V_0`, and :math:`P_0` are the instantaneous values at the start of the simulation. These can be overridden using the fix\_modify keywords *e0*\ , *v0*\ , and *p0* described below. @@ -179,19 +181,20 @@ instructions on how to use the accelerated styles effectively. **Restart, fix\_modify, output, run start/stop, minimize info:** -This fix writes the values of E0, V0, and P0, as well as the -state of all the thermostat and barostat -variables to :doc:`binary restart files `. See the -:doc:`read_restart ` command for info on how to re-specify -a fix in an input script that reads a restart file, so that the -operation of the fix continues in an uninterrupted fashion. - -The :doc:`fix_modify ` *e0*\ , *v0* and *p0* keywords -can be used to define the values of E0, V0, and P0. Note the -the values for *e0* and *v0* are extensive, and so must correspond -to the total energy and volume of the entire system, not energy and -volume per atom. If any of these quantities are not specified, then the -instantaneous value in the system at the start of the simulation is used. +This fix writes the values of :math:`E_0`, :math:`V_0`, and :math:`P_0`, +as well as the state of all the thermostat and barostat variables to +:doc:`binary restart files `. See the :doc:`read_restart +` command for info on how to re-specify a fix in an input +script that reads a restart file, so that the operation of the fix +continues in an uninterrupted fashion. + +The :doc:`fix_modify ` *e0*\ , *v0* and *p0* keywords can be +used to define the values of :math:`E_0`, :math:`V_0`, and +:math:`P_0`. Note the the values for *e0* and *v0* are extensive, and so +must correspond to the total energy and volume of the entire system, not +energy and volume per atom. If any of these quantities are not +specified, then the instantaneous value in the system at the start of +the simulation is used. The :doc:`fix_modify ` *temp* and *press* options are supported by these fixes. You can use them to assign a @@ -216,7 +219,7 @@ values are "intensive". The scalar is the cumulative energy change due to the fix. -The vector stores three quantities unique to this fix (Delta, Us, and up), +The vector stores three quantities unique to this fix (:math:`\Delta`, Us, and up), followed by all the internal Nose/Hoover thermostat and barostat variables defined for :doc:`fix npt `. Delta is the deviation of the temperature from the target temperature, given by the above equation. diff --git a/doc/src/fix_npt_cauchy.rst b/doc/src/fix_npt_cauchy.rst index 133305f13c..e9a98b813f 100644 --- a/doc/src/fix_npt_cauchy.rst +++ b/doc/src/fix_npt_cauchy.rst @@ -444,8 +444,26 @@ with *respa*\ , LAMMPS uses an integrator constructed according to the following factorization of the Liouville propagator (for two rRESPA levels): -.. image:: Eqs/fix_nh1.jpg - :align: center +.. math:: + + \exp \left(\mathrm{i} L \Delta t \right) = & \hat{E} + \exp \left(\mathrm{i} L_{\rm T\textrm{-}baro} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\rm T\textrm{-}part} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\epsilon , 2} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{2}^{(2)} \frac{\Delta t}{2} \right) \\ + &\times \left[ + \exp \left(\mathrm{i} L_{2}^{(1)} \frac{\Delta t}{2n} \right) + \exp \left(\mathrm{i} L_{\epsilon , 1} \frac{\Delta t}{2n} \right) + \exp \left(\mathrm{i} L_1 \frac{\Delta t}{n} \right) + \exp \left(\mathrm{i} L_{\epsilon , 1} \frac{\Delta t}{2n} \right) + \exp \left(\mathrm{i} L_{2}^{(1)} \frac{\Delta t}{2n} \right) + \right]^n \\ + &\times + \exp \left(\mathrm{i} L_{2}^{(2)} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\epsilon , 2} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\rm T\textrm{-}part} \frac{\Delta t}{2} \right) + \exp \left(\mathrm{i} L_{\rm T\textrm{-}baro} \frac{\Delta t}{2} \right) \\ + &+ \mathcal{O} \left(\Delta t^3 \right) This factorization differs somewhat from that of Tuckerman et al, in that the barostat is only updated at the outermost rRESPA level, diff --git a/doc/src/fix_nve_spin.rst b/doc/src/fix_nve_spin.rst index 6caa7cc8a6..c66d107089 100644 --- a/doc/src/fix_nve_spin.rst +++ b/doc/src/fix_nve_spin.rst @@ -47,7 +47,7 @@ By default a spin-lattice integration is performed (lattice = moving). The *nve/spin* fix applies a Suzuki-Trotter decomposition to the equations of motion of the spin lattice system, following the scheme: -.. image:: Eqs/fix_integration_spin_stdecomposition.jpg +.. image:: JPG/fix_integration_spin_stdecomposition.jpg :align: center according to the implementation reported in :ref:`(Omelyan) `. diff --git a/doc/src/fix_orient.rst b/doc/src/fix_orient.rst index 7100efc4e5..a23b98fbae 100644 --- a/doc/src/fix_orient.rst +++ b/doc/src/fix_orient.rst @@ -58,8 +58,22 @@ accounted for in measuring the grain boundary velocity. The potential energy added to atom I is given by these formulas -.. image:: Eqs/fix_orient_fcc.jpg - :align: center +.. math:: + + \xi_{i} = & \sum_{j=1}^{12} \left| \mathbf{r}_{j} - \mathbf{r}_{j}^{\rm I} \right| \qquad\qquad\left(1\right) \\ + \\ + \xi_{\rm IJ} = & \sum_{j=1}^{12} \left| \mathbf{r}_{j}^{\rm J} - \mathbf{r}_{j}^{\rm I} \right| \qquad\qquad\left(2\right)\\ + \\ + \xi_{\rm low} = & {\rm cutlo} \, \xi_{\rm IJ} \qquad\qquad\qquad\left(3\right)\\ + \xi_{\rm high} = & {\rm cuthi} \, \xi_{\rm IJ} \qquad\qquad\qquad\left(4\right) \\ + \\ + \omega_{i} = & \frac{\pi}{2} \frac{\xi_{i} - \xi_{\rm low}}{\xi_{\rm high} - \xi_{\rm low}} \qquad\qquad\left(5\right)\\ + \\ + u_{i} = & 0 \quad\quad\qquad\qquad\qquad \textrm{ for } \qquad \xi_{i} < \xi_{\rm low}\\ + = & {\rm dE}\,\frac{1 - \cos(2 \omega_{i})}{2} + \qquad \mathrm{ for }\qquad \xi_{\rm low} < \xi_{i} < \xi_{\rm high} \quad \left(6\right) \\ + = & {\rm dE} \quad\qquad\qquad\qquad\textrm{ for } \qquad \xi_{\rm high} < \xi_{i} + which are fully explained in :ref:`(Janssens) `. For fcc crystals this order parameter Xi for atom I in equation (1) is a sum over the diff --git a/doc/src/fix_pimd.rst b/doc/src/fix_pimd.rst index 436b13d9bc..d71c969acf 100644 --- a/doc/src/fix_pimd.rst +++ b/doc/src/fix_pimd.rst @@ -46,8 +46,11 @@ configurations from the canonical ensemble :ref:`(Feynman) `. The classical partition function and its components are given by the following equations: -.. image:: Eqs/fix_pimd.jpg - :align: center +.. math:: + + Z = & \int d{\bf q} d{\bf p} \cdot \textrm{exp} [ -\beta H_{eff} ] \\ + H_{eff} = & \bigg(\sum_{i=1}^P \frac{p_i^2}{2m_i}\bigg) + V_{eff} \\ + V_{eff} = & \sum_{i=1}^P \bigg[ \frac{mP}{2\beta^2 \hbar^2} (q_i - q_{i+1})^2 + \frac{1}{P} V(q_i)\bigg] The interested user is referred to any of the numerous references on this methodology, but briefly, each quantum particle in a path diff --git a/doc/src/fix_rhok.rst b/doc/src/fix_rhok.rst index ba381a37d3..9374f43798 100644 --- a/doc/src/fix_rhok.rst +++ b/doc/src/fix_rhok.rst @@ -29,8 +29,12 @@ Description The fix applies a force to atoms given by the potential -.. image:: Eqs/fix_rhok.jpg - :align: center +.. math:: + + U = & \frac{1}{2} K (|\rho_{\vec{k}}| - a)^2 \\ + \rho_{\vec{k}} = & \sum_j^N \exp(-i\vec{k} \cdot \vec{r}_j )/\sqrt{N} \\ + \vec{k} = & (2\pi n_x /L_x , 2\pi n_y /L_y , 2\pi n_z/L_z ) + as described in :ref:`(Pedersen) `. diff --git a/doc/src/fix_rx.rst b/doc/src/fix_rx.rst index ce40a58524..2f0df1ebd5 100644 --- a/doc/src/fix_rx.rst +++ b/doc/src/fix_rx.rst @@ -46,13 +46,17 @@ defined within the file associated with this command. For a general reaction such that -.. image:: Eqs/fix_rx_reaction.jpg - :align: center +.. math:: + + \nu_{A}A + \nu_{B}B \rightarrow \nu_{C}C + the reaction rate equation is defined to be of the form -.. image:: Eqs/fix_rx_reactionRate.jpg - :align: center +.. math:: + + r = k(T)[A]^{\nu_{A}}[B]^{\nu_{B}} + In the current implementation, the exponents are defined to be equal to the stoichiometric coefficients. A given reaction set consisting @@ -121,12 +125,14 @@ irreversible reaction. After specifying the reaction, the reaction rate constant is determined through the temperature dependent Arrhenius equation: -.. image:: Eqs/fix_rx.jpg - :align: center +.. math:: + + k = AT^{n}e^{\frac{-E_{a}}{k_{B}T}} + where *A* is the Arrhenius factor in time units or concentration/time units, *n* is the unitless exponent of the temperature dependence, and -*E\_a* is the activation energy in energy units. The temperature +:math:`E_a` is the activation energy in energy units. The temperature dependence can be removed by specifying the exponent as zero. The internal temperature of the coarse-grained particles can be used @@ -136,13 +142,17 @@ be specified to compute a local-average particle internal temperature for use in the reaction rate constant expressions. The local-average particle internal temperature is defined as: -.. image:: Eqs/fix_rx_localTemp.jpg - :align: center +.. math:: + + \theta_i^{-1} = \frac{\sum_{j=1}\omega_{Lucy}\left(r_{ij}\right)\theta_j^{-1}}{\sum_{j=1}\omega_{Lucy}\left(r_{ij}\right)} + where the Lucy function is expressed as: -.. image:: Eqs/fix_rx_localTemp2.jpg - :align: center +.. math:: + + \omega_{Lucy}\left(r_{ij}\right) = \left( 1 + \frac{3r_{ij}}{r_c} \right) \left( 1 - \frac{r_{ij}}{r_c} \right)^3 + The self-particle interaction is included in the above equation. diff --git a/doc/src/fix_shake.rst b/doc/src/fix_shake.rst index bca1a55d16..624d5cf455 100644 --- a/doc/src/fix_shake.rst +++ b/doc/src/fix_shake.rst @@ -75,13 +75,18 @@ be the position and velocity of atom *i* at time *n*\ , for *i* =1,...,\ *N*\ , where *N* is the number of sites of our reference molecule. The distance vector between sites *i* and *j* is given by -.. image:: Eqs/fix_rattle_rij.jpg - :align: center +.. math:: + + \mathbf r^{n+1}_{ij} = \mathbf r^n_j - \mathbf r^n_i + The constraints can then be formulated as -.. image:: Eqs/fix_rattle_constraints.jpg - :align: center +.. math:: + + \mathbf r^{n+1}_{ij} \cdot \mathbf r^{n+1}_{ij} &= d^2_{ij} \quad \text{and} \\ + \mathbf v^{n+1}_{ij} \cdot \mathbf r^{n+1}_{ij} &= 0 + The SHAKE algorithm satisfies the first condition, i.e. the sites at time *n+1* will have the desired separations Dij immediately after the diff --git a/doc/src/fix_spring_rg.rst b/doc/src/fix_spring_rg.rst index e1463dc4e3..fd3b09754b 100644 --- a/doc/src/fix_spring_rg.rst +++ b/doc/src/fix_spring_rg.rst @@ -44,15 +44,21 @@ energy of the constraint and associated force on each atom is given by the second and third formulas, when the group is at a different RG than the target value RG0. -.. image:: Eqs/fix_spring_rg.jpg - :align: center +.. math:: -The (xi - center-of-mass) term is computed taking into account -periodic boundary conditions, m\_i is the mass of the atom, and M is -the mass of the entire group. Note that K is thus a force constant + {R_G}^2 & = \frac{1}{M}\sum_{i}^{N}{m_{i}\left( x_{i} - + \frac{1}{M}\sum_{j}^{N}{m_{j}x_{j}} \right)^{2}} \\ + E & = K\left( R_G - R_{G0} \right)^{2} \\ + F_{i} & = 2K\frac{m_{i}}{M}\left( 1-\frac{R_{G0}}{R_G} + \right)\left( x_{i} - \frac{1}{M}\sum_{j}^{N}{m_{j}x_{j}} \right) + + +The (:math:`x_i` - center-of-mass) term is computed taking into account +periodic boundary conditions, :math:`m_i` is the mass of the atom, and +*M* is the mass of the entire group. Note that K is thus a force constant for the aggregate force on the group of atoms, not a per-atom force. -If RG0 is specified as NULL, then the RG of the group is computed at +If :math:`R_{G0}` is specified as NULL, then the RG of the group is computed at the time the fix is specified, and that value is used as the target. **Restart, fix\_modify, output, run start/stop, minimize info:** diff --git a/doc/src/fix_ti_spring.rst b/doc/src/fix_ti_spring.rst index ec4599b519..152e3fbcac 100644 --- a/doc/src/fix_ti_spring.rst +++ b/doc/src/fix_ti_spring.rst @@ -48,8 +48,10 @@ The thermodynamic integration procedure is performed by rescaling the force on each atom. Given an atomic configuration the force (F) on each atom is given by -.. image:: Eqs/fix_ti_spring_force.jpg - :align: center +.. math:: + + F = \left( 1-\lambda \right) F_{\text{solid}} + \lambda F_{\text{harm}} + where F\_solid is the force that acts on an atom due to an interatomic potential (\ *e.g.* EAM potential), F\_harm is the force due to the @@ -87,15 +89,19 @@ The *function* keyword allows the use of two different lambda paths. Option *1* results in a constant rate of change of lambda with time: -.. image:: Eqs/fix_ti_spring_function_1.jpg - :align: center +.. math:: + + \lambda(\tau) = \tau + where tau is the scaled time variable *t/t\_s*. The option *2* performs the lambda switching at a rate defined by the following switching function -.. image:: Eqs/fix_ti_spring_function_2.jpg - :align: center +.. math:: + + \lambda(\tau) = \tau^5 \left( 70 \tau^4 - 315 \tau^3 + 540 \tau^2 - 420 \tau + 126 \right) + This function has zero slope as lambda approaches its extreme values (0 and 1), according to :ref:`de Koning ` this results in diff --git a/doc/src/fix_ttm.rst b/doc/src/fix_ttm.rst index eeafd8bfe0..022afc67b5 100644 --- a/doc/src/fix_ttm.rst +++ b/doc/src/fix_ttm.rst @@ -109,8 +109,12 @@ Energy transport within the electronic subsystem is solved according to the heat diffusion equation with added source terms for heat transfer between the subsystems: -.. image:: Eqs/fix_ttm.jpg - :align: center +.. math:: + + C_e \rho_e \frac{\partial T_e}{\partial t} = + \bigtriangledown (\kappa_e \bigtriangledown T_e) - + g_p (T_e - T_a) + g_s T_a' + where C\_e is the specific heat, rho\_e is the density, kappa\_e is the thermal conductivity, T is temperature, the "e" and "a" subscripts @@ -194,8 +198,12 @@ temperature controlled by another fix - e.g. :doc:`fix nvt ` or Fix ttm/mod uses the heat diffusion equation with possible external heat sources (e.g. laser heating in ablation simulations): -.. image:: Eqs/fix_ttm_mod.jpg - :align: center +.. math:: + + C_e \rho_e \frac{\partial T_e}{\partial t} = + \bigtriangledown (\kappa_e \bigtriangledown T_e) - + g_p (T_e - T_a) + g_s T_a' + \theta (x-x_{surface})I_0 \exp(-x/l_{skin}) + where theta is the Heaviside step function, I\_0 is the (absorbed) laser pulse intensity for ablation simulations, l\_skin is the depth @@ -207,8 +215,10 @@ Fix ttm/mod also allows users to specify the dependencies of C\_e and kappa\_e on the electronic temperature. The specific heat is expressed as -.. image:: Eqs/fix_ttm_ce.jpg - :align: center +.. math:: + + C_e = C_0 + (a_0 + a_1 X + a_2 X^2 + a_3 X^3 + a_4 X^4) \exp (-(AX)^2) + where *X* = T\_e/1000, and the thermal conductivity is defined as kappa\_e = D\_e\*rho\_e\*C\_e, where D\_e is the thermal diffusion @@ -219,8 +229,10 @@ for the blast force acting on ions because of electronic pressure gradient (see :ref:`(Chen) `, :ref:`(Norman) `). The total force acting on an ion is: -.. image:: Eqs/fix_ttm_blast.jpg - :align: center +.. math:: + + {\vec F}_i = - \partial U / \partial {\vec r}_i + {\vec F}_{langevin} - \nabla P_e/n_{ion} + where F\_langevin is a force from Langevin thermostat simulating electron-phonon coupling, and nabla P\_e/n\_ion is the electron blast @@ -242,8 +254,10 @@ initial borders of vacuum can be set in the *init\_file* via *lsurface* and *rsurface* parameters. In this case, electronic pressure gradient is calculated as -.. image:: Eqs/fix_ttm_blast1.jpg - :align: center +.. math:: + + \nabla_x P_e = \left[\frac{C_e{}T_e(x)\lambda}{(x+\lambda)^2} + \frac{x}{x+\lambda}\frac{(C_e{}T_e)_{x+\Delta x}-(C_e{}T_e)_{x}}{\Delta x} \right] + where lambda is the electron mean free path (see :ref:`(Norman) `, :ref:`(Pisarev) `) diff --git a/doc/src/fix_wall.rst b/doc/src/fix_wall.rst index ba37b19205..600c880f20 100644 --- a/doc/src/fix_wall.rst +++ b/doc/src/fix_wall.rst @@ -104,35 +104,58 @@ wall-particle interactions depends on the style. For style *wall/lj93*\ , the energy E is given by the 9/3 potential: -.. image:: Eqs/fix_wall_lj93.jpg - :align: center +.. math:: + + E = \epsilon \left[ \frac{2}{15} \left(\frac{\sigma}{r}\right)^{9} - + \left(\frac{\sigma}{r}\right)^3 \right] + \qquad r < r_c + For style *wall/lj126*\ , the energy E is given by the 12/6 potential: -.. image:: Eqs/pair_lj.jpg - :align: center +.. math:: + + E = 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - + \left(\frac{\sigma}{r}\right)^6 \right] + \qquad r < r_c + For style *wall/lj1043*\ , the energy E is given by the 10/4/3 potential: -.. image:: Eqs/fix_wall_lj1043.jpg - :align: center +.. math:: + + E = 2 \pi \epsilon \left[ \frac{2}{5} \left(\frac{\sigma}{r}\right)^{10} - + \left(\frac{\sigma}{r}\right)^4 - + \frac{\sqrt(2)\sigma^3}{3\left(r+\left(0.61/\sqrt(2)\right)\sigma\right)^3}\right] + \qquad r < r_c + For style *wall/colloid*\ , the energy E is given by an integrated form of the :doc:`pair_style colloid ` potential: -.. image:: Eqs/fix_wall_colloid.jpg - :align: center +.. math:: + + E = & \epsilon \left[ \frac{\sigma^{6}}{7560} + \left(\frac{6R-D}{D^{7}} + \frac{D+8R}{(D+2R)^{7}} \right) \right. \\ + & \left. - \frac{1}{6} \left(\frac{2R(D+R) + D(D+2R) + \left[ \ln D - \ln (D+2R) \right]}{D(D+2R)} \right) \right] \qquad r < r_c + For style *wall/harmonic*\ , the energy E is given by a harmonic spring potential: -.. image:: Eqs/fix_wall_harmonic.jpg - :align: center +.. math:: + + E = \epsilon \quad (r - r_c)^2 \qquad r < r_c + For style *wall/morse*\ , the energy E is given by a Morse potential: -.. image:: Eqs/pair_morse.jpg - :align: center +.. math:: + + E = D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} \right] + \qquad r < r_c + In all cases, *r* is the distance from the particle to the wall at position *coord*\ , and Rc is the *cutoff* distance at which the diff --git a/doc/src/fix_wall_ees.rst b/doc/src/fix_wall_ees.rst index 6374109cc6..334228d85b 100644 --- a/doc/src/fix_wall_ees.rst +++ b/doc/src/fix_wall_ees.rst @@ -65,15 +65,16 @@ group by generating a force on the atom in a direction perpendicular to the wall and a torque parallel with the wall. The energy of wall-particle interactions E is given by: -.. image:: Eqs/fix_wall_ees.jpg - :align: center +.. math:: + + E = \epsilon \left[ \frac{2 \sigma_{LJ}^{12} \left(7 r^5+14 r^3 \sigma_{n}^2+3 r \sigma_{n}^4\right) }{945 \left(r^2-\sigma_{n}^2\right)^7} -\frac{ \sigma_{LJ}^6 \left(2 r \sigma_{n}^3+\sigma_{n}^2 \left(r^2-\sigma_{n}^2\right)\log{ \left[\frac{r-\sigma_{n}}{r+\sigma_{n}}\right]}\right) }{12 \sigma_{n}^5 \left(r^2-\sigma_{n}^2\right)} \right]\qquad \sigma_n < r < r_c + Introduced by Babadi and Ejtehadi in :ref:`(Babadi) `. Here, *r* is the distance from the particle to the wall at position *coord*\ , and Rc is the *cutoff* distance at which the particle and wall no -longer interact. Also, sigma\_n is the distance between center of -ellipsoid and the nearest point of its surface to the wall. The energy -of the wall is: +longer interact. Also, :math:`\sigma_n` is the distance between center of +ellipsoid and the nearest point of its surface to the wall as shown below. .. image:: JPG/fix_wall_ees_image.jpg :align: center @@ -82,24 +83,30 @@ Details of using this command and specifications are the same as fix/wall command. You can also find an example in USER/ees/ under examples/ directory. -The prefactor *epsilon* can be thought of as an +The prefactor :math:`\epsilon` can be thought of as an effective Hamaker constant with energy units for the strength of the -ellipsoid-wall interaction. More specifically, the *epsilon* pre-factor -= 8 \* pi\^2 \* rho\_wall \* rho\_ellipsoid \* epsilon -\* sigma\_a \* sigma\_b \* sigma\_c, where epsilon is the LJ parameters for -the constituent LJ particles and sigma\_a, sigma\_b, and sigma\_c are radii -of ellipsoidal particles. Rho\_wall and rho\_ellipsoid are the number -density of the constituent particles, in the wall and ellipsoid -respectively, in units of 1/volume. +ellipsoid-wall interaction. More specifically, the :math:`\epsilon` +pre-factor is + +.. math:: + + 8 \pi^2 \quad \rho_{wall} \quad \rho_{ellipsoid} \quad \epsilon \quad \sigma_a \quad \sigma_b \quad \sigma_c + + +where :math:`\epsilon` is the LJ energy parameter for the constituent LJ +particles and :math:`\sigma_a`, :math:`\sigma_b`, and :math:`\sigma_c` +are the radii of the ellipsoidal particles. :math:`\rho_{wall}` and +:math:`\rho_{ellipsoid}` are the number density of the constituent +particles, in the wall and ellipsoid respectively, in units of 1/volume. .. note:: - You must insure that r is always bigger than sigma\_n for + You must insure that r is always bigger than :math:`\sigma_n` for all particles in the group, or LAMMPS will generate an error. This means you cannot start your simulation with particles touching the wall - position *coord* (r = sigma\_n) or with particles penetrating the wall - (0 =< r < sigma\_n) or with particles on the wrong side of the - wall (r < 0). + position *coord* (:math:`r = \sigma_n`) or with particles penetrating + the wall (:math:`0 =< r < \sigma_n`) or with particles on the wrong + side of the wall (:math:`r < 0`). Fix *wall/region/ees* treats the surface of the geometric region defined by the *region-ID* as a bounding wall which interacts with nearby diff --git a/doc/src/fix_wall_region.rst b/doc/src/fix_wall_region.rst index 162b9d6994..a6f719e142 100644 --- a/doc/src/fix_wall_region.rst +++ b/doc/src/fix_wall_region.rst @@ -132,38 +132,62 @@ style. For style *lj93*\ , the energy E is given by the 9/3 potential: -.. image:: Eqs/fix_wall_lj93.jpg - :align: center +.. math:: + + E = \epsilon \left[ \frac{2}{15} \left(\frac{\sigma}{r}\right)^{9} - + \left(\frac{\sigma}{r}\right)^3 \right] + \qquad r < r_c + For style *lj126*\ , the energy E is given by the 12/6 potential: -.. image:: Eqs/pair_lj.jpg - :align: center +.. math:: + + E = 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - + \left(\frac{\sigma}{r}\right)^6 \right] + \qquad r < r_c + For style *wall/lj1043*\ , the energy E is given by the 10/4/3 potential: -.. image:: Eqs/fix_wall_lj1043.jpg - :align: center +.. math:: + + E = 2 \pi \epsilon \left[ \frac{2}{5} \left(\frac{\sigma}{r}\right)^{10} - + \left(\frac{\sigma}{r}\right)^4 - + \frac{\sqrt(2)\sigma^3}{3\left(r+\left(0.61/\sqrt(2)\right)\sigma\right)^3}\right] + \qquad r < r_c + For style *colloid*\ , the energy E is given by an integrated form of the :doc:`pair_style colloid ` potential: -.. image:: Eqs/fix_wall_colloid.jpg - :align: center +.. math:: + + E = & \epsilon \left[ \frac{\sigma^{6}}{7560} + \left(\frac{6R-D}{D^{7}} + \frac{D+8R}{(D+2R)^{7}} \right) \right. \\ + & \left. - \frac{1}{6} \left(\frac{2R(D+R) + D(D+2R) + \left[ \ln D - \ln (D+2R) \right]}{D(D+2R)} \right) \right] \qquad r < r_c + For style *wall/harmonic*\ , the energy E is given by a harmonic spring potential (the distance parameter is ignored): -.. image:: Eqs/fix_wall_harmonic.jpg - :align: center +.. math:: + + E = \epsilon \quad (r - r_c)^2 \qquad r < r_c + For style *wall/morse*\ , the energy E is given by the Morse potential: -.. image:: Eqs/pair_morse.jpg - :align: center +.. math:: + + E = D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} \right] + \qquad r < r_c + -Unlike other styles, this requires three parameters (*D\_0*, *alpha*\ , *r\_0* -in this order) instead of two like for the other wall styles. +Unlike other styles, this requires three parameters (:math:`D_0`, +:math:`\alpha`, and :math:`r_0` in this order) instead of two like +for the other wall styles. In all cases, *r* is the distance from the particle to the region surface, and Rc is the *cutoff* distance at which the particle and diff --git a/doc/src/min_style.rst b/doc/src/min_style.rst index 5de407b6a9..dffacab8a5 100644 --- a/doc/src/min_style.rst +++ b/doc/src/min_style.rst @@ -65,21 +65,21 @@ Style *fire* is a damped dynamics method described in :ref:`(Bitzek) and alters the projection operation to maintain components of the velocity non-parallel to the current force vector. The velocity of each atom is initialized to 0.0 by this style, at the beginning of a -minimization. This style correspond to an optimized version described +minimization. This style correspond to an optimized version described in :ref:`(Guenole) ` that include different time integration -schemes and defaults parameters. The default parameters can be +schemes and defaults parameters. The default parameters can be modified with the command :doc:`min_modify `. -Style *fire/old* is the original implementation of *fire* in Lammps, -conserved for backward compatibility. The main differences regarding +Style *fire/old* is the original implementation of *fire* in Lammps, +conserved for backward compatibility. The main differences regarding the current version *fire* are: time integration by Explicit Euler only, different sequence in maintaining velocity components non-parallel to the current force vector and hard-coded minimization parameters. -A complete description of the differences between *fire/old* and *fire* -can be found in :ref:`(Guenole) ` (where the current *fire* -in lammps is named *fire2.0*). By using an appropriate set of -parameters, *fire* can behave similarly than *fire/old*, as described +A complete description of the differences between *fire/old* and *fire* +can be found in :ref:`(Guenole) ` (where the current *fire* +in LAMMPS is called *fire2.0*). By using an appropriate set of +parameters, *fire* can behave similar to *fire/old*, as described in the :doc:`min_modify ` command. Style *spin* is a damped spin dynamics with an adaptive timestep. diff --git a/doc/src/pair_adp.rst b/doc/src/pair_adp.rst index 69051f545e..43a94933ad 100644 --- a/doc/src/pair_adp.rst +++ b/doc/src/pair_adp.rst @@ -1,16 +1,16 @@ -.. index:: pair\_style adp +.. index:: pair_style adp -pair\_style adp command -======================= +pair_style adp command +====================== -pair\_style adp/omp command -=========================== +pair_style adp/omp command +========================== Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style adp @@ -18,11 +18,11 @@ Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style adp - pair_coeff \* \* Ta.adp Ta - pair_coeff \* \* ../potentials/AlCu.adp Al Al Cu + pair_coeff * * Ta.adp Ta + pair_coeff * * ../potentials/AlCu.adp Al Al Cu Description """"""""""" @@ -32,15 +32,21 @@ using the angular dependent potential (ADP) of :ref:`(Mishin) `, which is a generalization of the :doc:`embedded atom method (EAM) potential `. The LAMMPS implementation is discussed in :ref:`(Singh) `. The total energy Ei of an atom I is given by -.. image:: Eqs/pair_adp.jpg - :align: center +.. math:: -where F is the embedding energy which is a function of the atomic -electron density rho, phi is a pair potential interaction, alpha and -beta are the element types of atoms I and J, and s and t = 1,2,3 and -refer to the cartesian coordinates. The mu and lambda terms represent -the dipole and quadruple distortions of the local atomic environment -which extend the original EAM framework by introducing angular forces. + E_i & = F_\alpha \left( \sum_{j\neq i} \rho_\beta (r_{ij}) \right) + \frac{1}{2} \sum_{j\neq i}\phi_{\alpha\beta}(r_{ij})+ \frac{1}{2} \sum_s (\mu_i^s)^2 + \frac{1}{2} \sum_{s,t} (\lambda_i^{st})^2 - \frac{1}{6} \nu_i^2 \\ + \mu_i^s & = \sum_{j\neq i}u_{\alpha\beta}(r_{ij})r_{ij}^s\\ + \lambda_i^{st} & = \sum_{j\neq i}w_{\alpha\beta}(r_{ij})r_{ij}^sr_{ij}^t\\ + \nu_i & = \sum_s\lambda_i^{ss} + + +where :math:`F` is the embedding energy which is a function of the atomic +electron density :math:`\rho`, :math:`\phi` is a pair potential interaction, +:math:`\alpha` and :math:`\beta` are the element types of atoms :math:`I` and +:math:`J`, and :math:`s` and :math:`t = 1,2,3` and refer to the cartesian +coordinates. The :math:`\mu` and :math:`\lambda` terms represent the dipole +and quadruple distortions of the local atomic environment which extend the +original EAM framework by introducing angular forces. Note that unlike for other potentials, cutoffs for ADP potentials are not set in the pair\_style or pair\_coeff command; they are specified in @@ -61,12 +67,12 @@ command to specify them. Only a single pair\_coeff command is used with the *adp* style which specifies an extended DYNAMO *setfl* file, which contains information -for M elements. These are mapped to LAMMPS atom types by specifying N +for :math:`M` elements. These are mapped to LAMMPS atom types by specifying :math:`N` additional arguments after the filename in the pair\_coeff command, -where N is the number of LAMMPS atom types: +where :math:`N` is the number of LAMMPS atom types: * filename -* N element names = mapping of extended *setfl* elements to atom types +* :math:`N` element names = mapping of extended *setfl* elements to atom types See the :doc:`pair_coeff ` doc page for alternate ways to specify the path for the potential file. @@ -79,9 +85,9 @@ and you want the 1st 3 to be Al, and the 4th to be Cu, you would use the following pair\_coeff command: -.. parsed-literal:: +.. code-block:: LAMMPS - pair_coeff \* \* AlCu.adp Al Al Al Cu + pair_coeff * * AlCu.adp Al Al Al Cu The 1st 2 arguments must be \* \* so as to span all LAMMPS atom types. The first three Al arguments map LAMMPS atom types 1,2,3 to the Al @@ -103,29 +109,33 @@ the tabulated pair potentials. See the :doc:`pair_eam ` command for further details on the *setfl* format. * lines 1,2,3 = comments (ignored) -* line 4: Nelements Element1 Element2 ... ElementN -* line 5: Nrho, drho, Nr, dr, cutoff +* line 4: :math:`N_{\text{elements}}` Element1 Element2 ... ElementN +* line 5: :math:`N_\rho`, :math:`d_\rho`, :math:`N_r`, :math:`d_r`, cutoff -Following the 5 header lines are Nelements sections, one for each +Following the 5 header lines are :math:`N_{\text{elements}}` sections, one for each element, each with the following format: * line 1 = atomic number, mass, lattice constant, lattice type (e.g. FCC) -* embedding function F(rho) (Nrho values) -* density function rho(r) (Nr values) - -Following the Nelements sections, Nr values for each pair potential -phi(r) array are listed for all i,j element pairs in the same format -as other arrays. Since these interactions are symmetric (i,j = j,i) -only phi arrays with i >= j are listed, in the following order: i,j = -(1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1), ..., (Nelements, -Nelements). The tabulated values for each phi function are listed as -r\*phi (in units of eV-Angstroms), since they are for atom pairs, the +* embedding function :math:`F(\rho)` (:math:`N_\rho` values) +* density function :math:`\rho(r)` (:math:`N_r` values) + +Following the :math:`N_{\text{elements}}` sections, :math:`N_r` values for each pair potential +:math:`\phi(r)` array are listed for all :math:`i,j` element pairs in the same format +as other arrays. Since these interactions are symmetric (:math:`i,j = j,i`) +only :math:`\phi` arrays with :math:`i \geq j` are listed, in the following order: + +.. math:: + + i,j = (1,1), (2,1), (2,2), (3,1), (3,2), (3,3), (4,1), ..., (N_{\text{elements}},N_{\text{elements}}). + +The tabulated values for each :math:`\phi` function are listed as +:math:`r*\phi` (in units of eV-Angstroms), since they are for atom pairs, the same as for :doc:`other EAM files `. -After the phi(r) arrays, each of the u(r) arrays are listed in the +After the :math:`\phi(r)` arrays, each of the :math:`u(r)` arrays are listed in the same order with the same assumptions of symmetry. Directly following -the u(r), the w(r) arrays are listed. Note that phi(r) is the only -array tabulated with a scaling by r. +the :math:`u(r)`, the :math:`w(r)` arrays are listed. Note that :math:`\phi(r)` is the only +array tabulated with a scaling by :math:`r`. ---------- diff --git a/doc/src/pair_agni.rst b/doc/src/pair_agni.rst index fc2b47b63d..bb7408f363 100644 --- a/doc/src/pair_agni.rst +++ b/doc/src/pair_agni.rst @@ -1,23 +1,26 @@ -.. index:: pair\_style agni +.. index:: pair_style agni -pair\_style agni command +pair_style agni command ======================== -pair\_style agni/omp command +pair_style agni/omp command ============================ Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style agni Examples """""""" -pair\_style agni -pair\_coeff \* \* Al.agni Al + +.. code-block:: LAMMPS + + pair_style agni + pair_coeff * * Al.agni Al Description """"""""""" @@ -25,14 +28,19 @@ Description Style *agni* style computes the many-body vectorial force components for an atom as -.. image:: Eqs/pair_agni.jpg - :align: center +.. math:: + + F_i^u & = \sum_t^{N_t}\alpha_t \cdot \exp\left[-\frac{\left(d_{i,t}^u\right)^2}{2l^2}\right] \\ + d_{i,t}^u & = \left|\left| V_i^u(\eta) - V_t^u(\eta) \right|\right| \\ + V_i^u(\eta) & = \sum_{j \neq i}\frac{r^u_{ij}}{r_{ij}} \cdot e^{-\left(\frac{r_{ij}}{\eta} \right)^2} \cdot f_d\left(r_{ij}\right) \\ + f_d\left(r_{ij}\right) & = \frac{1}{2} \left[\cos\left(\frac{\pi r_{ij}}{R_c}\right) + 1 \right] + -*u* labels the individual components, i.e. x, y or z, and *V* is the -corresponding atomic fingerprint. *d* is the Euclidean distance between -any two atomic fingerprints. A total of N\_t reference atomic -environments are considered to construct the force field file. *alpha\_t* -and *l* are the weight coefficients and length scale parameter of the +:math:`u` labels the individual components, i.e. :math:`x`, :math:`y` or :math:`z`, and :math:`V` is the +corresponding atomic fingerprint. :math:`d` is the Euclidean distance between +any two atomic fingerprints. A total of :math:`N_t` reference atomic +environments are considered to construct the force field file. :math:`\alpha_t` +and :math:`l` are the weight coefficients and length scale parameter of the non-linear regression model. The method implements the recently proposed machine learning access to @@ -45,11 +53,11 @@ vectorial atomic forces. Only a single pair\_coeff command is used with the *agni* style which specifies an AGNI potential file containing the parameters of the force field for the needed elements. These are mapped to LAMMPS atom -types by specifying N additional arguments after the filename in the -pair\_coeff command, where N is the number of LAMMPS atom types: +types by specifying :math:`N` additional arguments after the filename in the +pair\_coeff command, where :math:`N` is the number of LAMMPS atom types: * filename -* N element names = mapping of AGNI elements to atom types +* :math:`N` element names = mapping of AGNI elements to atom types See the :doc:`pair_coeff ` doc page for alternate ways to specify the path for the force field file. diff --git a/doc/src/pair_airebo.rst b/doc/src/pair_airebo.rst index 0cd2a79fe8..e2ef285f91 100644 --- a/doc/src/pair_airebo.rst +++ b/doc/src/pair_airebo.rst @@ -1,61 +1,61 @@ -.. index:: pair\_style airebo +.. index:: pair_style airebo -pair\_style airebo command -========================== +pair_style airebo command +========================= -pair\_style airebo/intel command -================================ +pair_style airebo/intel command +=============================== -pair\_style airebo/omp command -============================== +pair_style airebo/omp command +============================= -pair\_style airebo/morse command -================================ +pair_style airebo/morse command +=============================== -pair\_style airebo/morse/intel command -====================================== +pair_style airebo/morse/intel command +===================================== -pair\_style airebo/morse/omp command -==================================== +pair_style airebo/morse/omp command +=================================== -pair\_style rebo command -======================== +pair_style rebo command +======================= -pair\_style rebo/intel command -============================== +pair_style rebo/intel command +============================= -pair\_style rebo/omp command -============================ +pair_style rebo/omp command +=========================== Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style style cutoff LJ_flag TORSION_flag cutoff_min * style = *airebo* or *airebo/morse* or *rebo* -* cutoff = LJ or Morse cutoff (sigma scale factor) (AIREBO and AIREBO-M only) +* cutoff = LJ or Morse cutoff (:math:`\sigma` scale factor) (AIREBO and AIREBO-M only) * LJ\_flag = 0/1 to turn off/on the LJ or Morse term (AIREBO and AIREBO-M only, optional) * TORSION\_flag = 0/1 to turn off/on the torsion term (AIREBO and AIREBO-M only, optional) -* cutoff\_min = Start of the transition region of cutoff (sigma scale factor) (AIREBO and AIREBO-M only, optional) +* cutoff\_min = Start of the transition region of cutoff (:math:`\sigma` scale factor) (AIREBO and AIREBO-M only, optional) Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style airebo 3.0 pair_style airebo 2.5 1 0 - pair_coeff \* \* ../potentials/CH.airebo H C + pair_coeff * * ../potentials/CH.airebo H C pair_style airebo/morse 3.0 - pair_coeff \* \* ../potentials/CH.airebo-m H C + pair_coeff * * ../potentials/CH.airebo-m H C pair_style rebo - pair_coeff \* \* ../potentials/CH.rebo H C + pair_coeff * * ../potentials/CH.rebo H C Description """"""""""" @@ -82,8 +82,11 @@ with a few slightly different parameters The AIREBO potential consists of three terms: -.. image:: Eqs/pair_airebo.jpg - :align: center +.. math:: + + E & = \frac{1}{2} \sum_i \sum_{j \neq i} + \left[ E^{\text{REBO}}_{ij} + E^{\text{LJ}}_{ij} + + \sum_{k \neq i,j} \sum_{l \neq i,j,k} E^{\text{TORSION}}_{kijl} \right] \\ By default, all three terms are included. For the *airebo* style, if the first two optional flag arguments to the pair\_style command are @@ -91,73 +94,73 @@ included, the LJ and torsional terms can be turned off. Note that both or neither of the flags must be included. If both of the LJ an torsional terms are turned off, it becomes the 2nd-generation REBO potential, with a small caveat on the spline fitting procedure -mentioned below. This can be specified directly as pair\_style *rebo* +mentioned below. This can be specified directly as pair_style *rebo* with no additional arguments. The detailed formulas for this potential are given in :ref:`(Stuart) `; here we provide only a brief description. -The E\_REBO term has the same functional form as the hydrocarbon REBO +The :math:`E^{\text{REBO}}` term has the same functional form as the hydrocarbon REBO potential developed in :ref:`(Brenner) `. The coefficients for -E\_REBO in AIREBO are essentially the same as Brenner's potential, but +:math:`E^{\text{REBO}}` in AIREBO are essentially the same as Brenner's potential, but a few fitted spline values are slightly different. For most cases the -E\_REBO term in AIREBO will produce the same energies, forces and +:math:`E^{\text{REBO}}` term in AIREBO will produce the same energies, forces and statistical averages as the original REBO potential from which it was -derived. The E\_REBO term in the AIREBO potential gives the model its +derived. The :math:`E^{\text{REBO}}` term in the AIREBO potential gives the model its reactive capabilities and only describes short-ranged C-C, C-H and H-H -interactions (r < 2 Angstroms). These interactions have strong +interactions (:math:`r < 2` Angstroms). These interactions have strong coordination-dependence through a bond order parameter, which adjusts the attraction between the I,J atoms based on the position of other nearby atoms and thus has 3- and 4-body dependence. -The E\_LJ term adds longer-ranged interactions (2 < r < cutoff) using a +The :math:`E^{\text{LJ}}` term adds longer-ranged interactions (:math:`2 < r < \text{cutoff}`) using a form similar to the standard :doc:`Lennard Jones potential `. -The E\_LJ term in AIREBO contains a series of switching functions so -that the short-ranged LJ repulsion (1/r\^12) does not interfere with -the energetics captured by the E\_REBO term. The extent of the E\_LJ -interactions is determined by the *cutoff* argument to the pair\_style +The :math:`E^{\text{LJ}}` term in AIREBO contains a series of switching functions so +that the short-ranged LJ repulsion (:math:`1/r^{12}`) does not interfere with +the energetics captured by the :math:`E^{\text{REBO}}` term. The extent of the :math:`E^{\text{LJ}}` +interactions is determined by the *cutoff* argument to the pair_style command which is a scale factor. For each type pair (C-C, C-H, H-H) the cutoff is obtained by multiplying the scale factor by the sigma value defined in the potential file for that type pair. In the -standard AIREBO potential, sigma\_CC = 3.4 Angstroms, so with a scale -factor of 3.0 (the argument in pair\_style), the resulting E\_LJ cutoff +standard AIREBO potential, :math:`\sigma_{CC} = 3.4` Angstroms, so with a scale +factor of 3.0 (the argument in pair_style), the resulting :math:`E^{\text{LJ}}` cutoff would be 10.2 Angstroms. By default, the longer-ranged interaction is smoothly switched off -between 2.16 and 3.0 sigma. By specifying *cutoff\_min* in addition +between 2.16 and 3.0 :math:`\sigma`. By specifying *cutoff\_min* in addition to *cutoff*\ , the switching can be configured to take place between *cutoff\_min* and *cutoff*\ . *cutoff\_min* can only be specified if all optional arguments are given. -The E\_TORSION term is an explicit 4-body potential that describes +The :math:`E^{\text{TORSION}}` term is an explicit 4-body potential that describes various dihedral angle preferences in hydrocarbon configurations. ---------- -Only a single pair\_coeff command is used with the *airebo*\ , *airebo* +Only a single pair_coeff command is used with the *airebo*\ , *airebo* or *rebo* style which specifies an AIREBO, REBO, or AIREBO-M potential file with parameters for C and H. Note that as of LAMMPS version 15 May 2019 the *rebo* style in LAMMPS uses its own potential file (CH.rebo). These are mapped to LAMMPS atom types by specifying -N additional arguments after the filename in the pair\_coeff command, +N additional arguments after the filename in the pair_coeff command, where N is the number of LAMMPS atom types: * filename -* N element names = mapping of AIREBO elements to atom types +* :math:`N` element names = mapping of AIREBO elements to atom types See the :doc:`pair_coeff ` doc page for alternate ways to specify the path for the potential file. As an example, if your LAMMPS simulation has 4 atom types and you want the 1st 3 to be C, and the 4th to be H, you would use the following -pair\_coeff command: +pair_coeff command: -.. parsed-literal:: +.. code-block:: LAMMPS - pair_coeff \* \* CH.airebo C C C H + pair_coeff * * CH.airebo C C C H The 1st 2 arguments must be \* \* so as to span all LAMMPS atom types. The first three C arguments map LAMMPS atom types 1,2,3 to the C @@ -178,21 +181,21 @@ listed in the CH.airebo-m file to agree with the :ref:`(O'Connor) ` paper. Thus the parameters are specific to this potential and the way it was fit, so modifying the file should be done cautiously. The AIREBO-M Morse potentials were parameterized using a cutoff of -3.0 (sigma). Modifying this cutoff may impact simulation accuracy. +3.0 (:math:`\sigma`). Modifying this cutoff may impact simulation accuracy. This pair style tallies a breakdown of the total AIREBO potential energy into sub-categories, which can be accessed via the :doc:`compute pair ` command as a vector of values of length 3. The 3 values correspond to the following sub-categories: -1. *E\_REBO* = REBO energy -2. *E\_LJ* = Lennard-Jones energy -3. *E\_TORSION* = Torsion energy +1. :math:`E_{\text{REBO}}` = REBO energy +2. :math:`E_{\text{LJ}}` = Lennard-Jones energy +3. :math:`E_{\text{TORSION}}` = Torsion energy To print these quantities to the log file (with descriptive column headings) the following commands could be included in an input script: -.. parsed-literal:: +.. code-block:: LAMMPS compute 0 all pair airebo variable REBO equal c_0[1] @@ -232,12 +235,12 @@ These pair styles do not support the :doc:`pair_modify ` mix, shift, table, and tail options. These pair styles do not write their information to :doc:`binary restart files `, since it is stored in potential files. Thus, you -need to re-specify the pair\_style and pair\_coeff commands in an input +need to re-specify the pair_style and pair_coeff commands in an input script that reads a restart file. These pair styles can only be used via the *pair* keyword of the :doc:`run_style respa ` command. They do not support the -*inner*\ , *middle*\ , *outer* keywords. +*inner* , *middle*, *outer* keywords. Restrictions """""""""""" diff --git a/doc/src/pair_atm.rst b/doc/src/pair_atm.rst index 6118b0943f..c8c4edeb54 100644 --- a/doc/src/pair_atm.rst +++ b/doc/src/pair_atm.rst @@ -1,13 +1,13 @@ -.. index:: pair\_style atm +.. index:: pair_style atm -pair\_style atm command -======================= +pair_style atm command +====================== Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style atm cutoff cutoff_triple @@ -18,13 +18,13 @@ Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style atm 4.5 2.5 - pair_coeff \* \* \* 0.072 + pair_coeff * * * 0.072 pair_style hybrid/overlay lj/cut 6.5 atm 4.5 2.5 - pair_coeff \* \* lj/cut 1.0 1.0 + pair_coeff * * lj/cut 1.0 1.0 pair_coeff 1 1 atm 1 0.064 pair_coeff 1 1 atm 2 0.080 pair_coeff 1 2 atm 2 0.100 @@ -36,91 +36,95 @@ Description The *atm* style computes a 3-body :ref:`Axilrod-Teller-Muto ` potential for the energy E of a system of atoms as -.. image:: Eqs/pair_atm.jpg - :align: center +.. math:: + + E & = \nu\frac{1+3\cos\gamma_1\cos\gamma_2\cos\gamma_3}{r_{12}^3r_{23}^3r_{31}^3} \\ + -where nu is the three-body interaction strength. The distances -between pairs of atoms r12, r23, r31 and the angles gamma1, gamma2, -gamma3 are as shown in this diagram: +where :math:`\nu` is the three-body interaction strength. The distances +between pairs of atoms :math:`r_{12}`, :math:`r_{23}`, :math:`r_{31}` and the angles :math:`\gamma_1`, :math:`\gamma_2`, +:math:`\gamma_3` are as shown in this diagram: .. image:: JPG/pair_atm_dia.jpg :align: center -Note that for the interaction between a triplet of atoms I,J,K, there +Note that for the interaction between a triplet of atoms :math:`I,J,K`, there is no "central" atom. The interaction is symmetric with respect to -permutation of the three atoms. Thus the nu value is -the same for all those permutations of the atom types of I,J,K +permutation of the three atoms. Thus the :math:`\nu` value is +the same for all those permutations of the atom types of :math:`I,J,K` and needs to be specified only once, as discussed below. The *atm* potential is typically used in combination with a two-body potential using the :doc:`pair_style hybrid/overlay ` command as in the example above. -The potential for a triplet of atom is calculated only if all 3 -distances r12, r23, r31 between the 3 atoms satisfy rIJ < cutoff. -In addition, the product of the 3 distances r12\*r23\*r31 < -cutoff\_triple\^3 is required, which excludes from calculation the -triplets with small contribution to the interaction. +The potential for a triplet of atom is calculated only if all 3 distances +:math:`r_{12}`, :math:`r_{23}`, :math:`r_{31}` between the 3 atoms satisfy +:math:`r_{IJ} < \text{cutoff}`. In addition, the product of the 3 distances +:math:`r_{12} r_{23} r_{31}` < cutoff_triple :math:`^3` is required, which +excludes from calculation the triplets with small contribution to the +interaction. The following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples above, or in the restart files read by the :doc:`read_restart ` commands: -* K = atom type of the third atom (1 to Ntypes) -* nu = prefactor (energy/distance\^9 units) +* :math:`K` = atom type of the third atom (1 to :math:`N_{\text{types}}`) +* :math:`\nu` = prefactor (energy/distance\^9 units) -K can be specified in one of two ways. An explicit numeric value can -be used, as in the 2nd example above. J <= K is required. LAMMPS -sets the coefficients for the other 5 symmetric interactions to the -same values. E.g. if I = 1, J = 2, K = 3, then these 6 values are set -to the specified nu: nu123, nu132, nu213, nu231, nu312, nu321. This -enforces the symmetry discussed above. +:math:`K` can be specified in one of two ways. An explicit numeric value can +be used, as in the 2nd example above. :math:`J \leq K` is required. LAMMPS +sets the coefficients for the other 5 symmetric interactions to the same +values. E.g. if :math:`I = 1`, :math:`J = 2`, :math:`K = 3`, then these 6 +values are set to the specified :math:`\nu`: :math:`\nu_{123}`, +:math:`\nu_{132}`, :math:`\nu_{213}`, :math:`\nu_{231}`, :math:`\nu_{312}`, +:math:`\nu_{321}`. This enforces the symmetry discussed above. A wildcard asterisk can be used for K to set the coefficients for multiple triplets of atom types. This takes the form "\*" or "\*n" or -"n\*" or "m\*n". If N = the number of atom types, then an asterisk with -no numeric values means all types from 1 to N. A leading asterisk -means all types from 1 to n (inclusive). A trailing asterisk means -all types from n to N (inclusive). A middle asterisk means all types -from m to n (inclusive). Note that only type triplets with J <= K are -considered; if asterisks imply type triplets where K < J, they are +"n\*" or "m\*n". If :math:`N` equals 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 :math:`n` (inclusive). A trailing asterisk means +all types from :math:`n` to :math:`N` (inclusive). A middle asterisk means all types +from :math:`m` to :math:`n` (inclusive). Note that only type triplets with :math:`J \leq K` are +considered; if asterisks imply type triplets where :math:`K < J`, they are ignored. -Note that a pair\_coeff command can override a previous setting for the -same I,J,K triplet. For example, these commands set nu for all I,J.K -triplets, then overwrite nu for just the I,J,K = 2,3,4 triplet: +Note that a pair_coeff command can override a previous setting for the +same :math:`I,J,K` triplet. For example, these commands set :math:`\nu` for all :math:`I,J.K` +triplets, then overwrite nu for just the :math:`I,J,K = 2,3,4` triplet: -.. parsed-literal:: +.. code-block:: LAMMPS - pair_coeff \* \* \* 0.25 + pair_coeff * * * 0.25 pair_coeff 2 3 4 0.1 Note that for a simulation with a single atom type, only a single entry is required, e.g. -.. parsed-literal:: +.. code-block:: LAMMPS pair_coeff 1 1 1 0.25 -For a simulation with two atom types, four pair\_coeff commands will +For a simulation with two atom types, four pair_coeff commands will specify all possible nu values: -.. parsed-literal:: +.. code-block:: LAMMPS pair_coeff 1 1 1 nu1 pair_coeff 1 1 2 nu2 pair_coeff 1 2 2 nu3 pair_coeff 2 2 2 nu4 -For a simulation with three atom types, ten pair\_coeff commands will +For a simulation with three atom types, ten pair_coeff commands will specify all possible nu values: -.. parsed-literal:: +.. code-block:: LAMMPS pair_coeff 1 1 1 nu1 pair_coeff 1 1 2 nu2 @@ -133,12 +137,12 @@ specify all possible nu values: pair_coeff 2 3 3 nu9 pair_coeff 3 3 3 nu10 -By default the nu value for all triplets is set to 0.0. Thus it is -not required to provide pair\_coeff commands that enumerate triplet -interactions for all K types. If some I,J,K combination is not +By default the :math:`\nu` value for all triplets is set to 0.0. Thus it is +not required to provide pair_coeff commands that enumerate triplet +interactions for all :math:`K` types. If some :math:`I,J,K` combination is not specified, then there will be no 3-body ATM interactions for that combination and all its permutations. However, as with all pair -styles, it is required to specify a pair\_coeff command for all I,J +styles, it is required to specify a pair_coeff command for all :math:`I,J` combinations, else an error will result. @@ -150,16 +154,16 @@ combinations, else an error will result. This pair styles do not support the :doc:`pair_modify ` mix, shift, table, and tail options. -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. -However, if the *atm* potential is used in combination with other -potentials using the :doc:`pair_style hybrid/overlay ` -command then pair\_coeff commands need to be re-specified -in the restart input script. +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. However, if the *atm* potential +is used in combination with other potentials using the :doc:`pair_style +hybrid/overlay ` command then pair_coeff commands need to be +re-specified in the restart input script. 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. +*inner* , *middle* , *outer* keywords. ---------- diff --git a/doc/src/pair_beck.rst b/doc/src/pair_beck.rst index 6a407e11a9..88abfe9798 100644 --- a/doc/src/pair_beck.rst +++ b/doc/src/pair_beck.rst @@ -1,19 +1,19 @@ -.. index:: pair\_style beck +.. index:: pair_style beck -pair\_style beck command -======================== +pair_style beck command +======================= -pair\_style beck/gpu command -============================ +pair_style beck/gpu command +=========================== -pair\_style beck/omp command -============================ +pair_style beck/omp command +=========================== Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style beck Rc @@ -23,10 +23,10 @@ Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style beck 8.0 - pair_coeff \* \* 399.671876712 0.0000867636112694 0.675 4.390 0.0003746 + pair_coeff * * 399.671876712 0.0000867636112694 0.675 4.390 0.0003746 pair_coeff 1 1 399.671876712 0.0000867636112694 0.675 4.390 0.0003746 6.0 Description @@ -36,8 +36,10 @@ Style *beck* computes interactions based on the potential by :ref:`(Beck) `, originally designed for simulation of Helium. It includes truncation at a cutoff distance Rc. -.. image:: Eqs/pair_beck.jpg - :align: center +.. math:: + + E(r) &= A \exp\left[-\alpha r - \beta r^6\right] - \frac{B}{\left(r^2+a^2\right)^3} \left(1+\frac{2.709+3a^2}{r^2+a^2}\right) \qquad r < R_c \\ + The following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples @@ -45,15 +47,15 @@ above, or in the data file or restart files read by the :doc:`read_data ` or :doc:`read_restart ` commands. -* A (energy units) -* B (energy-distance\^6 units) -* a (distance units) -* alpha (1/distance units) -* beta (1/distance\^6 units) +* :math:`A` (energy units) +* :math:`B` (energy-distance\^6 units) +* :math:`a` (distance units) +* :math:`\alpha` (1/distance units) +* :math:`\beta` (1/distance\^6 units) * cutoff (distance units) The last coefficient is optional. If not specified, the global cutoff -Rc is used. +:math:`R_c` is used. ---------- @@ -108,7 +110,7 @@ This pair style can only be used via the *pair* keyword of the Restrictions """""""""""" - none +none Related commands """""""""""""""" diff --git a/doc/src/pair_body_nparticle.rst b/doc/src/pair_body_nparticle.rst index 1214890070..edfd4f3ab2 100644 --- a/doc/src/pair_body_nparticle.rst +++ b/doc/src/pair_body_nparticle.rst @@ -1,13 +1,13 @@ -.. index:: pair\_style body/nparticle +.. index:: pair_style body/nparticle -pair\_style body/nparticle command -================================== +pair_style body/nparticle command +================================= Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style body/nparticle cutoff @@ -17,10 +17,10 @@ Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style body/nparticle 3.0 - pair_coeff \* \* 1.0 1.0 + pair_coeff * * 1.0 1.0 pair_coeff 1 1 1.0 1.5 2.5 Description @@ -67,11 +67,15 @@ The interaction between two sub-particles, or a sub-particle and point particle, or between two point particles is computed as a Lennard-Jones interaction, using the standard formula -.. image:: Eqs/pair_lj.jpg - :align: center +.. math:: -where Rc is the cutoff. As explained above, an interaction involving -one or two body sub-particles may be computed even for r > Rc. + E & = 4 \epsilon \left[ \left(\frac{\sigma}{r}\right)^{12} - + \left(\frac{\sigma}{r}\right)^6 \right] + \qquad r < R_c \\ + + +where :math:`R_c` is the cutoff. As explained above, an interaction involving +one or two body sub-particles may be computed even for :math:`r > R_c`. For style *body*\ , the following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in @@ -79,8 +83,8 @@ the examples above, or in the data file or restart files read by the :doc:`read_data ` or :doc:`read_restart ` commands: -* epsilon (energy units) -* sigma (distance units) +* :math:`\epsilon` (energy units) +* :math:`\sigma` (distance units) * cutoff (distance units) The last coefficient is optional. If not specified, the global cutoff @@ -94,7 +98,7 @@ is used. For atom type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff distance for all of this pair style can be mixed. The -default mix value is *geometric*\ . See the "pair\_modify" command for +default mix value is *geometric*\ . See the :doc:`pair_modify ` command for details. This pair style does not support the :doc:`pair_modify ` diff --git a/doc/src/pair_body_rounded_polygon.rst b/doc/src/pair_body_rounded_polygon.rst index 9a042b5b5a..652c618d4a 100644 --- a/doc/src/pair_body_rounded_polygon.rst +++ b/doc/src/pair_body_rounded_polygon.rst @@ -1,16 +1,19 @@ -.. index:: pair\_style body/rounded/polygon +.. index:: pair_style body/rounded/polygon -pair\_style body/rounded/polygon command -======================================== +pair_style body/rounded/polygon command +======================================= Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style body/rounded/polygon c_n c_t mu delta_ua cutoff + +.. parsed-literal:: + c_n = normal damping coefficient c_t = tangential damping coefficient mu = normal friction coefficient during gross sliding @@ -21,10 +24,10 @@ Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style body/rounded/polygon 20.0 5.0 0.0 1.0 0.5 - pair_coeff \* \* 100.0 1.0 + pair_coeff * * 100.0 1.0 pair_coeff 1 1 100.0 1.0 Description @@ -33,7 +36,8 @@ Description Style *body/rounded/polygon* is for use with 2d models of body particles of style *rounded/polygon*\ . It calculates pairwise body/body interactions which can include body particles modeled as -1-vertex circular disks with a specified diameter. See the :doc:`Howto body ` doc page for more details on using body +1-vertex circular disks with a specified diameter. See the +:doc:`Howto body ` doc page for more details on using body rounded/polygon particles. This pairwise interaction between rounded polygons is described in @@ -54,34 +58,44 @@ their respective rounded surfaces, not by the separation of the vertices and edges themselves. This means that the specified cutoff in the pair\_style command is the -cutoff distance, r\_c, for the surface separation, \delta\_n (see figure +cutoff distance, :math:`r_c`, for the surface separation, :math:`\delta_n` (see figure below). This is the distance at which two particles no longer -interact. If r\_c is specified as 0.0, then it is a contact-only +interact. If :math:`r_c` is specified as 0.0, then it is a contact-only interaction. I.e. the two particles must overlap in order to exert a -repulsive force on each other. If r\_c > 0.0, then the force between +repulsive force on each other. If :math:`r_c > 0.0`, then the force between two particles will be attractive for surface separations from 0 to -r\_c, and repulsive once the particles overlap. +:math:`r_c`, and repulsive once the particles overlap. Note that unlike for other pair styles, the specified cutoff is not the distance between the centers of two particles at which they stop interacting. This center-to-center distance depends on the shape and size of the two particles and their relative orientation. LAMMPS takes that into account when computing the surface separation distance -and applying the r\_c cutoff. +and applying the :math:`r_c` cutoff. The forces between vertex-vertex, vertex-edge, and edge-edge overlaps are given by: -.. image:: Eqs/pair_body_rounded.jpg - :align: center +.. math:: + + F_n &= \begin{cases} + k_n \delta_n - c_n v_n & \delta_n \le 0 \\ + -k_{na} \delta_n - c_n v_n & 0 < \delta_n \le r_c \\ + 0 & \delta_n > r_c \\ + \end{cases} \\ + F_t &= \begin{cases} + \mu k_n \delta_n - c_t v_t & \delta_n \le 0 \\ + 0 & \delta_n > 0 + \end{cases} .. image:: JPG/pair_body_rounded.jpg :align: center -Note that F\_n and F\_t are functions of the surface separation \delta\_n -= d - (R\_i + R\_j). In this model, when (R\_i + R\_j) < d < (R\_i + R\_j) -+ r\_c, that is, 0 < \delta\_n < r\_c, the cohesive region of the two -surfaces overlap and the two surfaces are attractive to each other. +Note that :math:`F_n` and :math:`F_t` are functions of the surface separation +:math:`\delta_n = d - (R_i + R_j)`. In this model, when +:math:`(R_i + R_j) < d < (R_i + R_j) + r_c`, that is, :math:`0 < \delta_n < r_c`, +the cohesive region of the two surfaces overlap and the two surfaces are +attractive to each other. In :ref:`Fraige `, the tangential friction force between two particles that are in contact is modeled differently prior to gross @@ -98,12 +112,12 @@ 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 read by the :doc:`read_data ` command: -* k\_n (energy/distance\^2 units) -* k\_na (energy/distance\^2 units) +* :math:`k_n` (energy/distance\^2 units) +* :math:`k_{na}` (energy/distance\^2 units) -Effectively, k\_n and k\_na are the slopes of the red lines in the plot -above for force versus surface separation, for \delta\_n < 0 and 0 < -\delta\_n < r\_c respectively. +Effectively, :math:`k_n` and :math:`k_{na}` are the slopes of the red lines in the plot +above for force versus surface separation, for :math:`\delta_n < 0` and +:math:`0 < \delta_n < r_c` respectively. **Mixing, shift, table, tail correction, restart, rRESPA info**\ : @@ -120,7 +134,6 @@ This pair style can only be used via the *pair* keyword of the Restrictions """""""""""" - These pair styles are part of the BODY package. They are only enabled if LAMMPS was built with that package. See the :doc:`Build package ` doc page for more info. diff --git a/doc/src/pair_body_rounded_polyhedron.rst b/doc/src/pair_body_rounded_polyhedron.rst index 23623a640e..20dbbafb13 100644 --- a/doc/src/pair_body_rounded_polyhedron.rst +++ b/doc/src/pair_body_rounded_polyhedron.rst @@ -1,16 +1,18 @@ -.. index:: pair\_style body/rounded/polyhedron +.. index:: pair_style body/rounded/polyhedron -pair\_style body/rounded/polyhedron command -=========================================== +pair_style body/rounded/polyhedron command +========================================== Syntax """""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style body/rounded/polyhedron c_n c_t mu delta_ua cutoff +.. parsed-literal:: + c_n = normal damping coefficient c_t = tangential damping coefficient mu = normal friction coefficient during gross sliding @@ -21,10 +23,10 @@ Examples """""""" -.. parsed-literal:: +.. code-block:: LAMMPS pair_style body/rounded/polyhedron 20.0 5.0 0.0 1.0 0.5 - pair_coeff \* \* 100.0 1.0 + pair_coeff * * 100.0 1.0 pair_coeff 1 1 100.0 1.0 Description @@ -33,7 +35,8 @@ Description Style *body/rounded/polygon* is for use with 3d models of body particles of style *rounded/polyhedron*\ . It calculates pairwise body/body interactions which can include body particles modeled as -1-vertex spheres with a specified diameter. See the :doc:`Howto body ` doc page for more details on using body +1-vertex spheres with a specified diameter. See the +:doc:`Howto body ` doc page for more details on using body rounded/polyhedron particles. This pairwise interaction between the rounded polyhedra is described @@ -54,26 +57,35 @@ separation of their respective rounded surfaces, not by the separation of the vertices, edges, and faces themselves. This means that the specified cutoff in the pair\_style command is the -cutoff distance, r\_c, for the surface separation, \delta\_n (see figure +cutoff distance, :math:`r_c`, for the surface separation, :math:`\delta_n` (see figure below). This is the distance at which two particles no longer -interact. If r\_c is specified as 0.0, then it is a contact-only +interact. If :math:`r_c` is specified as 0.0, then it is a contact-only interaction. I.e. the two particles must overlap in order to exert a -repulsive force on each other. If r\_c > 0.0, then the force between +repulsive force on each other. If :math:`r_c > 0.0`, then the force between two particles will be attractive for surface separations from 0 to -r\_c, and repulsive once the particles overlap. +:math:`r_c`, and repulsive once the particles overlap. Note that unlike for other pair styles, the specified cutoff is not the distance between the centers of two particles at which they stop interacting. This center-to-center distance depends on the shape and size of the two particles and their relative orientation. LAMMPS takes that into account when computing the surface separation distance -and applying the r\_c cutoff. +and applying the :math:`r_c` cutoff. The forces between vertex-vertex, vertex-edge, vertex-face, edge-edge, and edge-face overlaps are given by: -.. image:: Eqs/pair_body_rounded.jpg - :align: center +.. math:: + + F_n &= \begin{cases} + k_n \delta_n - c_n v_n, & \delta_n \le 0 \\ + -k_{na} \delta_n - c_n v_n & 0 < \delta_n \le r_c \\ + 0 & \delta_n > r_c \\ + \end{cases} \\ + F_t &= \begin{cases} + \mu k_n \delta_n - c_t v_t & \delta_n \le 0 \\ + 0 & \delta_n > 0 + \end{cases} .. image:: JPG/pair_body_rounded.jpg :align: center @@ -93,20 +105,21 @@ 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 read by the :doc:`read_data ` command: -* k\_n (energy/distance\^2 units) -* k\_na (energy/distance\^2 units) +* :math:`k_n` (energy/distance\^2 units) +* :math:`k_{na}` (energy/distance\^2 units) -Effectively, k\_n and k\_na are the slopes of the red lines in the plot -above for force versus surface separation, for \delta\_n < 0 and 0 < -\delta\_n < r\_c respectively. +Effectively, :math:`k_n` and :math:`k_{na}` are the slopes of the red lines in the plot +above for force versus surface separation, for :math:`\delta_n` < 0 and +:math:`0 < \delta_n < r_c` respectively. **Mixing, shift, table, tail correction, restart, rRESPA info**\ : This pair style does not support the :doc:`pair_modify ` mix, shift, table, and tail options. -This pair style does not write its 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 write its 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 can only be used via the *pair* keyword of the :doc:`run_style respa ` command. It does not support the diff --git a/doc/src/pair_fep_soft.rst b/doc/src/pair_fep_soft.rst index 20bd84a567..263b52cacf 100644 --- a/doc/src/pair_fep_soft.rst +++ b/doc/src/pair_fep_soft.rst @@ -187,8 +187,14 @@ are suited for "alchemical" free energy calculations using the :doc:`fix adapt/f The *lj/cut/soft* style and related sub-styles compute the 12-6 Lennard-Jones and Coulomb potentials modified by a soft core, with the functional form -.. image:: Eqs/pair_lj_soft.jpg - :align: center +.. math:: + + E = \lambda^n 4 \epsilon \left\{ + \frac{1}{ \left[ \alpha_{\mathrm{LJ}} (1-\lambda)^2 + + \left( \displaystyle\frac{r}{\sigma} \right)^6 \right]^2 } - + \frac{1}{ \alpha_{\mathrm{LJ}} (1-\lambda)^2 + + \left( \displaystyle\frac{r}{\sigma} \right)^6 } + \right\} \qquad r < r_c The *lj/class2/soft* style is a 9-6 potential with the exponent of the denominator of the first term in brackets taking the value 1.5 instead of 2 @@ -197,25 +203,30 @@ denominator of the first term in brackets taking the value 1.5 instead of 2 Coulomb interactions can also be damped with a soft core at short distance, -.. image:: Eqs/pair_coul_soft.jpg - :align: center +.. math:: + + E = \lambda^n \frac{ C q_i q_j}{\epsilon \left[ \alpha_{\mathrm{C}} + (1-\lambda)^2 + r^2 \right]^{1/2}} \qquad r < r_c -In the Coulomb part C is an energy-conversion constant, q\_i and q\_j -are the charges on the 2 atoms, and epsilon is the dielectric constant -which can be set by the :doc:`dielectric ` command. +In the Coulomb part :math:`C` is an energy-conversion constant, :math:`q_i` and +:math:`q_j` are the charges on the 2 atoms, and epsilon is the dielectric +constant which can be set by the :doc:`dielectric ` command. -The coefficient lambda is an activation parameter. When lambda = 1 the pair -potential is identical to a Lennard-Jones term or a Coulomb term or a -combination of both. When lambda = 0 the interactions are deactivated. The -transition between these two extrema is smoothed by a soft repulsive core in -order to avoid singularities in potential energy and forces when sites are -created or annihilated and can overlap :ref:`(Beutler) `. +The coefficient lambda is an activation parameter. When :math:`\lambda = 1` the +pair potential is identical to a Lennard-Jones term or a Coulomb term or a +combination of both. When :math:`\lambda = 0` the interactions are +deactivated. The transition between these two extrema is smoothed by a soft +repulsive core in order to avoid singularities in potential energy and forces +when sites are created or annihilated and can overlap :ref:`(Beutler) +`. -The parameters n, alpha\_LJ and alpha\_C are set in the -:doc:`pair_style ` command, before the cutoffs. Usual choices for the -exponent are n = 2 or n = 1. For the remaining coefficients alpha\_LJ = 0.5 and -alpha\_C = 10 Angstrom\^2 are appropriate choices. Plots of the 12/6 LJ and -Coulomb terms are shown below, for lambda ranging from 1 to 0 every 0.1. +The parameters :math:`n`, :math:`\alpha_\mathrm{LJ}` and +:math:`\alpha_\mathrm{C}` are set in the :doc:`pair_style ` command, +before the cutoffs. Usual choices for the exponent are :math:`n = 2` or +:math:`n = 1`. For the remaining coefficients :math:`\alpha_\mathrm{LJ} = 0.5` +and :math:`\alpha_\mathrm{C} = 10~\text{A}^2` are appropriate choices. Plots of +the 12-6 LJ and Coulomb terms are shown below, for lambda ranging from 1 to 0 +every 0.1. .. image:: JPG/lj_soft.jpg .. image:: JPG/coul_soft.jpg @@ -225,12 +236,12 @@ For the *lj/cut/coul/cut/soft* or *lj/cut/coul/long/soft* pair styles, as well as for the equivalent *class2* versions, the following coefficients must be defined for each pair of atoms 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: +the :doc:`read_data ` or :doc:`read_restart ` commands, +or by mixing as described below: -* epsilon (energy units) -* sigma (distance units) -* lambda (activation parameter, between 0 and 1) +* :math:`\epsilon` (energy units) +* :math:`\sigma` (distance units) +* :math:`\lambda` (activation parameter, between 0 and 1) * cutoff1 (distance units) * cutoff2 (distance units) @@ -245,61 +256,62 @@ since it has no Coulombic terms. For the *coul/cut/soft* and specified. Style *lj/cut/tip4p/long/soft* implements a soft-core version of the TIP4P water -model. The usage of the TIP4P pair style is documented in the -:doc:`pair_lj ` styles. In the soft version the parameters n, alpha\_LJ -and alpha\_C are set in the :doc:`pair_style ` command, after the -specific parameters of the TIP4P water model and before the cutoffs. The -activation parameter lambda is supplied as an argument of the -:doc:`pair_coeff ` command, after epsilon and sigma and before the -optional cutoffs. +model. The usage of the TIP4P pair style is documented in the :doc:`pair_lj +` styles. In the soft version the parameters :math:`n`, +:math:`\alpha_\mathrm{LJ}` and :math:`\alpha_\mathrm {C}` are set in the +:doc:`pair_style ` command, after the specific parameters of the +TIP4P water model and before the cutoffs. The activation parameter lambda is +supplied as an argument of the :doc:`pair_coeff ` command, after +epsilon and sigma and before the optional cutoffs. Style *lj/charmm/coul/long/soft* implements a soft-core version of the modified -12-6 LJ potential used in CHARMM and documented in the -:doc:`pair_style lj/charmm/coul/long ` style. In the soft version the parameters n, -alpha\_LJ and alpha\_C are set in the :doc:`pair_style ` command, before -the global cutoffs. The activation parameter lambda is introduced as an argument -of the :doc:`pair_coeff ` command, after epsilon and sigma and -before the optional eps14 and sigma14. +12-6 LJ potential used in CHARMM and documented in the :doc:`pair_style +lj/charmm/coul/long ` style. In the soft version the parameters +:math:`n`, :math:`\alpha_\mathrm{LJ}` and :math:`\alpha_\mathrm{C}` are set in +the :doc:`pair_style ` command, before the global cutoffs. The +activation parameter lambda is introduced as an argument of the :doc:`pair_coeff +` command, after :math:`\epsilon` and :math:`\sigma` and before the +optional eps14 and sigma14. Style *lj/class2/soft* implements a soft-core version of the 9-6 potential in -:doc:`pair_style lj/class2 `. In the soft version the parameters n, alpha\_LJ -and alpha\_C are set in the :doc:`pair_style ` command, before the -global cutoffs. The activation parameter lambda is introduced as an argument of -the the :doc:`pair_coeff ` command, after epsilon and sigma and before -the optional cutoffs. - -The *coul/cut/soft*\ , *coul/long/soft* and *tip4p/long/soft* sub-styles -are designed to be combined with other pair potentials via the -:doc:`pair_style hybrid/overlay ` command. This is because -they have no repulsive core. Hence, if used by themselves, there will -be no repulsion to keep two oppositely charged particles from -overlapping each other. In this case, if lambda = 1, a singularity may -occur. These sub-styles are suitable to represent charges embedded in -the Lennard-Jones radius of another site (for example hydrogen atoms -in several water models). +:doc:`pair_style lj/class2 `. In the soft version the parameters +:math:`n`, :math:`\alpha_\mathrm{LJ}` and :math:`\alpha_\mathrm{C}` are set in the +:doc:`pair_style ` command, before the global cutoffs. The +activation parameter lambda is introduced as an argument of the the +:doc:`pair_coeff ` command, after :math:`\epsilon` and +:math:`\sigma` and before the optional cutoffs. + +The *coul/cut/soft*\ , *coul/long/soft* and *tip4p/long/soft* sub-styles are +designed to be combined with other pair potentials via the :doc:`pair_style +hybrid/overlay ` command. This is because they have no repulsive +core. Hence, if used by themselves, there will be no repulsion to keep two +oppositely charged particles from overlapping each other. In this case, if +:math:`\lambda = 1`, a singularity may occur. These sub-styles are suitable to +represent charges embedded in the Lennard-Jones radius of another site (for +example hydrogen atoms in several water models). .. note:: - When using the soft-core Coulomb potentials with long-range - solvers (\ *coul/long/soft*\ , *lj/cut/coul/long/soft*\ , etc.) in a free - energy calculation in which sites holding electrostatic charges are - being created or annihilated (using :doc:`fix adapt/fep ` - and :doc:`compute fep `) it is important to adapt both the - lambda activation parameter (from 0 to 1, or the reverse) and the - value of the charge (from 0 to its final value, or the reverse). This - ensures that long-range electrostatic terms (kspace) are correct. It - is not necessary to use soft-core Coulomb potentials if the van der - Waals site is present during the free-energy route, thus avoiding - overlap of the charges. Examples are provided in the LAMMPS source - directory tree, under examples/USER/fep. + When using the soft-core Coulomb potentials with long-range solvers (\ + *coul/long/soft*\ , *lj/cut/coul/long/soft*\ , etc.) in a free energy + calculation in which sites holding electrostatic charges are being created or + annihilated (using :doc:`fix adapt/fep ` and :doc:`compute fep + `) it is important to adapt both the :math:`\lambda` activation + parameter (from 0 to 1, or the reverse) and the value of the charge (from 0 + to its final value, or the reverse). This ensures that long-range + electrostatic terms (kspace) are correct. It is not necessary to use + soft-core Coulomb potentials if the van der Waals site is present during the + free-energy route, thus avoiding overlap of the charges. Examples are + provided in the LAMMPS source directory tree, under examples/USER/fep. .. note:: - To avoid division by zero do not set sigma = 0 in the *lj/cut/soft* and - related styles; use the lambda parameter instead to activate/deactivate - interactions, or use epsilon = 0 and sigma = 1. Alternatively, when sites do not - interact though the Lennard-Jones term the *coul/long/soft* or similar sub-style - can be used via the :doc:`pair_style hybrid/overlay ` command. + To avoid division by zero do not set :math:`\sigma = 0` in the *lj/cut/soft* + and related styles; use the lambda parameter instead to activate/deactivate + interactions, or use :math:`\epsilon = 0` and :math:`\sigma = 1`. + Alternatively, when sites do not interact though the Lennard-Jones term + the *coul/long/soft* or similar sub-style can be used via the + :doc:`pair_style hybrid/overlay ` command. ---------- @@ -309,15 +321,25 @@ The *morse/soft* variant modifies the :doc:`pair_morse ` style at short range to have a soft core. The functional form differs from that of the *lj/soft* styles, and is instead given by: -.. image:: Eqs/pair_morse_soft.jpg - :align: center +.. math:: + + \begin{split} + s(\lambda) =& (1 - \lambda) / (1 - \lambda_f), \qquad B = -2D e^{-2 \alpha + r_0} (e^{\alpha r_0} - 1) / 3 \\ + E =& D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} \right] + + s(\lambda) B e^{-3\alpha(r-r_0)}, \qquad \hspace{2.85em}\lambda \geq + \lambda_f,\quad r < r_c \\ + E =& \left( D_0 \left[ e^{- 2 \alpha (r - r_0)} - 2 e^{- \alpha (r - r_0)} + \right] + B e^{-3\alpha(r-r_0)} \right)(\lambda/\lambda_f)^n, \qquad \lambda + < \lambda_f,\quad r < r_c + \end{split} The *morse/soft* style requires the following pair coefficients: -* D0 (energy units) -* alpha (1/distance units) -* r0 (distance units) -* lambda (unitless, between 0.0 and 1.0) +* :math:`D_0` (energy units) +* :math:`\alpha` (1/distance units) +* :math:`r_0` (distance units) +* :math:`\lambda` (unitless, between 0.0 and 1.0) * cutoff (distance units) The last coefficient is optional. If not specified, the global morse cutoff is @@ -338,9 +360,10 @@ These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, USER-OMP and OPT packages, respectively. They are only enabled if LAMMPS was built with those packages. See the :doc:`Build package ` doc page for more info. -You can specify the accelerated styles explicitly in your input script -by including their suffix, or you can use the :doc:`-suffix command-line switch ` when you invoke LAMMPS, or you can use the -:doc:`suffix ` command in your input script. +You can specify the accelerated styles explicitly in your input script by +including their suffix, or you can use the :doc:`-suffix command-line switch +` when you invoke LAMMPS, or you can use the :doc:`suffix ` +command in your input script. See the :doc:`Speed packages ` doc page for more instructions on how to use the accelerated styles effectively. @@ -351,16 +374,16 @@ instructions on how to use the accelerated styles effectively. **Mixing, shift, tail correction, restart info**\ : -The different versions of the *lj/cut/soft* pair styles support mixing. For atom -type pairs I,J and I != J, the epsilon and sigma coefficients and cutoff -distance for these pair style can be mixed. The default mix value is -*geometric* for 12-6 styles. +The different versions of the *lj/cut/soft* pair styles support mixing. For +atom type pairs I,J and I != J, the :math:`\epsilon` and :math:`\sigma` +coefficients and cutoff distance for these pair style can be mixed. The default +mix value is *geometric* for 12-6 styles. -The mixing rule for epsilon and sigma for *lj/class2/soft* 9-6 potentials is to use the -*sixthpower* formulas. The :doc:`pair_modify mix ` setting is thus -ignored for class2 potentials for epsilon and sigma. However it is still -followed for mixing the cutoff distance. See the :doc:`pair_modify ` -command for details. +The mixing rule for epsilon and sigma for *lj/class2/soft* 9-6 potentials is to +use the *sixthpower* formulas. The :doc:`pair_modify mix ` setting +is thus ignored for class2 potentials for :math:`\epsilon` and +:math:`\sigma`. However it is still followed for mixing the cutoff distance. See +the :doc:`pair_modify ` command for details. The *morse/soft* pair style does not support mixing. Thus, coefficients for all LJ pairs must be specified explicitly. @@ -376,22 +399,25 @@ interaction. .. note:: - The analytical form of the tail corrections for energy and pressure used - in the *lj/cut/soft* potentials are approximate, being identical to that of the - corresponding non-soft potentials scaled by a factor lambda\^n. The errors due to - this approximation should be negligible. For example, for a cutoff of 2.5 sigma - this approximation leads to maximum relative errors in tail corrections of the - order of 1e-4 for energy and virial (alpha\_LJ = 0.5, n = 2). The error vanishes - when lambda approaches 0 or 1. Note that these are the errors affecting the - long-range tail (itself a correction to the interaction energy) which includes - other approximations, namely that the system is homogeneous (local density equal + The analytical form of the tail corrections for energy and pressure used in + the *lj/cut/soft* potentials are approximate, being identical to that of the + corresponding non-soft potentials scaled by a factor :math:`\lambda^n`. The + errors due to this approximation should be negligible. For example, for a + cutoff of :math:`2.5\sigma` this approximation leads to maximum relative + errors in tail corrections of the order of 1e-4 for energy and virial + (:math:`\alpha_\mathrm{LJ} = 0.5, n = 2`). The error vanishes when lambda + approaches 0 or 1. Note that these are the errors affecting the long-range + tail (itself a correction to the interaction energy) which includes other + approximations, namely that the system is homogeneous (local density equal the average density) beyond the cutoff. -The *morse/soft* pair style does not support the :doc:`pair_modify ` -tail option for adding long-range tail corrections to energy and pressure. +The *morse/soft* pair style does not support the :doc:`pair_modify +` tail option for adding long-range tail corrections to energy and +pressure. -All of these pair styles write 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. +All of these pair styles write 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. ---------- diff --git a/doc/src/pair_nm.rst b/doc/src/pair_nm.rst index f8ae4f7a91..6d319c6d06 100644 --- a/doc/src/pair_nm.rst +++ b/doc/src/pair_nm.rst @@ -68,22 +68,25 @@ by :ref:`Clarke `, mainly used for ionic liquids. A site can represent a single atom or a united-atom site. The energy of an interaction has the following form: -.. image:: Eqs/pair_nm.jpg - :align: center +.. math:: -Rc is the cutoff. + E = \frac{E_0}{(n-m)} \left[ m \left(\frac{r_0}{r}\right)^n - n + \left(\frac{r_0}{r}\right)^m \right] \qquad r < r_c + +where :math:`r_c` is the cutoff. Style *nm/cut/coul/cut* adds a Coulombic pairwise interaction given by -.. image:: Eqs/pair_coulomb.jpg - :align: center +.. math:: + + E = \frac{C q_i q_j}{\epsilon r} \qquad r < r_c -where C is an energy-conversion constant, Qi and Qj are the charges on -the 2 atoms, and epsilon is the dielectric constant which can be set -by the :doc:`dielectric ` command. If one cutoff is -specified in the pair\_style command, it is used for both the NM and -Coulombic terms. If two cutoffs are specified, they are used as -cutoffs for the NM and Coulombic terms respectively. +where :math:`C` is an energy-conversion constant, :math:`q_i` and :math:`q_j` +are the charges on the 2 atoms, and epsilon is the dielectric constant which can +be set by the :doc:`dielectric ` command. If one cutoff is +specified in the pair\_style command, it is used for both the N-M and Coulombic +terms. If two cutoffs are specified, they are used as cutoffs for the N-M and +Coulombic terms respectively. Styles *nm/cut/coul/long* compute the same Coulombic interactions as style *nm/cut/coul/cut* except that an @@ -101,22 +104,22 @@ examples above, or in the data file or restart files read by the :doc:`read_data ` or :doc:`read_restart ` commands. -* E0 (energy units) -* r0 (distance units) -* n (unitless) -* m (unitless) +* :math:`E_0` (energy units) +* :math:`r_0` (distance units) +* :math:`n` (unitless) +* :math:`m` (unitless) * cutoff1 (distance units) * cutoff2 (distance units) The latter 2 coefficients are optional. If not specified, the global -NM and Coulombic cutoffs specified in the pair\_style command are used. -If only one cutoff is specified, it is used as the cutoff for both NM +N-M and Coulombic cutoffs specified in the pair\_style command are used. +If only one cutoff is specified, it is used as the cutoff for both N-M and Coulombic interactions for this type pair. If both coefficients -are specified, they are used as the NM and Coulombic cutoffs for this +are specified, they are used as the N-M and Coulombic cutoffs for this type pair. You cannot specify 2 cutoffs for style *nm*\ , since it has no Coulombic terms. -For *nm/cut/coul/long* only the NM cutoff can be specified since a +For *nm/cut/coul/long* only the N-M cutoff can be specified since a Coulombic cutoff cannot be specified for an individual I,J type pair. All type pairs use the same global Coulombic cutoff specified in the pair\_style command. @@ -140,7 +143,7 @@ the short-range portion of the long-range Coulombic interaction. All of the *nm* pair styles support the :doc:`pair_modify ` tail option for adding a long-range tail correction to the energy and -pressure for the NM portion of the pair interaction. +pressure for the N-M portion of the pair interaction. All of the *nm* pair styles write their 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. diff --git a/doc/src/pair_srp.rst b/doc/src/pair_srp.rst index a1138db382..822bd0dddb 100644 --- a/doc/src/pair_srp.rst +++ b/doc/src/pair_srp.rst @@ -56,19 +56,25 @@ Bonds of specified type *btype* interact with one another through a bond-pairwise potential, such that the force on bond *i* due to bond *j* is as follows -.. image:: Eqs/pair_srp1.jpg - :align: center +.. math:: -where *r* and *rij* are the distance and unit vector between the two -bonds. Note that *btype* can be specified as an asterisk "\*", which -case the interaction is applied to all bond types. The *mid* option -computes *r* and *rij* from the midpoint distance between bonds. The -*min* option computes *r* and *rij* from the minimum distance between -bonds. The force acting on a bond is mapped onto the two bond atoms -according to the lever rule, + F^{SRP}_{ij} & = C(1-r/r_c)\hat{r}_{ij} \qquad r < r_c + + +where *r* and :math:`\hat{r}_{ij}` are the distance and unit vector +between the two bonds. Note that *btype* can be specified as an +asterisk "\*", which case the interaction is applied to all bond types. +The *mid* option computes *r* and :math:`\hat{r}_{ij}` from the midpoint +distance between bonds. The *min* option computes *r* and +:math:`\hat{r}_{ij}` from the minimum distance between bonds. The force +acting on a bond is mapped onto the two bond atoms according to the +lever rule, + +.. math:: + + F_{i1}^{SRP} & = F^{SRP}_{ij}(L) \\ + F_{i2}^{SRP} & = F^{SRP}_{ij}(1-L) -.. image:: Eqs/pair_srp2.jpg - :align: center where *L* is the normalized distance from the atom to the point of closest approach of bond *i* and *j*\ . The *mid* option takes *L* as @@ -80,7 +86,7 @@ the data file or restart file read by the :doc:`read_data ` or :doc:`read_restart ` commands: * *C* (force units) -* *rc* (distance units) +* :math:`r_c` (distance units) The last coefficient is optional. If not specified, the global cutoff is used. @@ -114,7 +120,7 @@ Pair style *srp* turns off normalization of thermodynamic properties by particle number, as if the command :doc:`thermo_modify norm no ` had been issued. The pairwise energy associated with style *srp* is shifted to be zero -at the cutoff distance *rc*\ . +at the cutoff distance :math:`r_c`. ---------- @@ -127,7 +133,7 @@ This pair styles does not support mixing. This pair style does not support the :doc:`pair_modify ` shift option for the energy of the pair interaction. Note that as discussed above, the energy term is already shifted to be 0.0 at the -cutoff distance *rc*\ . +cutoff distance :math:`r_c`. The :doc:`pair_modify ` table option is not relevant for this pair style. diff --git a/doc/src/pair_sw.rst b/doc/src/pair_sw.rst index 425dcf1f16..2df9958ba1 100644 --- a/doc/src/pair_sw.rst +++ b/doc/src/pair_sw.rst @@ -39,12 +39,23 @@ Description The *sw* style computes a 3-body :ref:`Stillinger-Weber ` potential for the energy E of a system of atoms as -.. image:: Eqs/pair_sw.jpg - :align: center +.. math:: -where phi2 is a two-body term and phi3 is a three-body term. The -summations in the formula are over all neighbors J and K of atom I -within a cutoff distance = a\*sigma. + E & = \sum_i \sum_{j > i} \phi_2 (r_{ij}) + + \sum_i \sum_{j \neq i} \sum_{k > j} + \phi_3 (r_{ij}, r_{ik}, \theta_{ijk}) \\ + \phi_2(r_{ij}) & = A_{ij} \epsilon_{ij} \left[ B_{ij} (\frac{\sigma_{ij}}{r_{ij}})^{p_{ij}} - + (\frac{\sigma_{ij}}{r_{ij}})^{q_{ij}} \right] + \exp \left( \frac{\sigma_{ij}}{r_{ij} - a_{ij} \sigma_{ij}} \right) \\ + \phi_3(r_{ij},r_{ik},\theta_{ijk}) & = \lambda_{ijk} \epsilon_{ijk} \left[ \cos \theta_{ijk} - + \cos \theta_{0ijk} \right]^2 + \exp \left( \frac{\gamma_{ij} \sigma_{ij}}{r_{ij} - a_{ij} \sigma_{ij}} \right) + \exp \left( \frac{\gamma_{ik} \sigma_{ik}}{r_{ik} - a_{ik} \sigma_{ik}} \right) + + +where :math:`\phi_2` is a two-body term and :math:`\phi_3` is a +three-body term. The summations in the formula are over all neighbors J +and K of atom I within a cutoff distance :math:`a `\sigma`. Only a single pair\_coeff command is used with the *sw* style which specifies a Stillinger-Weber potential file with parameters for all @@ -86,24 +97,25 @@ and three-body coefficients in the formula above: * element 1 (the center atom in a 3-body interaction) * element 2 * element 3 -* epsilon (energy units) -* sigma (distance units) +* :math:`\epsilon` (energy units) +* :math:`\sigma` (distance units) * a -* lambda -* gamma -* costheta0 +* :math:`\lambda` +* :math:`\gamma` +* :math:`\cos\theta_0` * A * B * p * q * tol -The A, B, p, and q parameters are used only for two-body -interactions. The lambda and costheta0 parameters are used only for -three-body interactions. The epsilon, sigma and a parameters are used -for both two-body and three-body interactions. gamma is used only in the -three-body interactions, but is defined for pairs of atoms. -The non-annotated parameters are unitless. +The A, B, p, and q parameters are used only for two-body interactions. +The :math:`\lambda` and :math:`\cos\theta_0` parameters are used only +for three-body interactions. The :math:`\epsilon`, :math:`\sigma` and +*a* parameters are used for both two-body and three-body +interactions. :math:`\gamma` is used only in the three-body +interactions, but is defined for pairs of atoms. The non-annotated +parameters are unitless. LAMMPS introduces an additional performance-optimization parameter tol that is used for both two-body and three-body interactions. In the @@ -141,9 +153,9 @@ are usually defined by simple formulas involving two sets of pair-wise parameters, corresponding to the ij and ik pairs, where i is the center atom. The user must ensure that the correct combining rule is used to calculate the values of the three-body parameters for -alloys. Note also that the function phi3 contains two exponential +alloys. Note also that the function :math:`\phi_3` contains two exponential screening factors with parameter values from the ij pair and ik -pairs. So phi3 for a C atom bonded to a Si atom and a second C atom +pairs. So :math:`\phi_3` for a C atom bonded to a Si atom and a second C atom will depend on the three-body parameters for the CSiC entry, and also on the two-body parameters for the CCC and CSiSi entries. Since the order of the two neighbors is arbitrary, the three-body parameters for @@ -152,8 +164,8 @@ parameters for entries SiCC and CSiSi should also be the same. The parameters used only for two-body interactions (A, B, p, and q) in entries whose 2nd and 3rd element are different (e.g. SiCSi) are not used for anything and can be set to 0.0 if desired. -This is also true for the parameters in phi3 that are -taken from the ij and ik pairs (sigma, a, gamma) +This is also true for the parameters in :math:`\phi_3` that are +taken from the ij and ik pairs (:math:`\sigma`, *a*\ , :math:`\gamma`) ---------- diff --git a/doc/src/pair_tersoff.rst b/doc/src/pair_tersoff.rst index ab9d714499..f2e44d0362 100644 --- a/doc/src/pair_tersoff.rst +++ b/doc/src/pair_tersoff.rst @@ -50,12 +50,28 @@ Description The *tersoff* style computes a 3-body Tersoff potential :ref:`(Tersoff\_1) ` for the energy E of a system of atoms as -.. image:: Eqs/pair_tersoff_1.jpg - :align: center - -where f\_R is a two-body term and f\_A includes three-body interactions. -The summations in the formula are over all neighbors J and K of atom I -within a cutoff distance = R + D. +.. math:: + + E & = \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\ + V_{ij} & = f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) \right] \\ + f_C(r) & = \left\{ \begin{array} {r@{\quad:\quad}l} + 1 & r < R - D \\ + \frac{1}{2} - \frac{1}{2} \sin \left( \frac{\pi}{2} \frac{r-R}{D} \right) & + R-D < r < R + D \\ + 0 & r > R + D + \end{array} \right. \\ + f_R(r) & = A \exp (-\lambda_1 r) \\ + f_A(r) & = -B \exp (-\lambda_2 r) \\ + b_{ij} & = \left( 1 + \beta^n {\zeta_{ij}}^n \right)^{-\frac{1}{2n}} \\ + \zeta_{ij} & = \sum_{k \neq i,j} f_C(r_{ik}) g(\theta_{ijk}) + \exp \left[ {\lambda_3}^m (r_{ij} - r_{ik})^m \right] \\ + g(\theta) & = \gamma_{ijk} \left( 1 + \frac{c^2}{d^2} - + \frac{c^2}{\left[ d^2 + (\cos \theta - \cos \theta_0)^2\right]} \right) + + +where :math:`f_R` is a two-body term and :math:`f_A` includes three-body +interactions. The summations in the formula are over all neighbors +J and K of atom I within a cutoff distance = R + D. The *tersoff/table* style uses tabulated forms for the two-body, environment and angular functions. Linear interpolation is performed @@ -104,22 +120,24 @@ above: * element 2 (the atom bonded to the center atom) * element 3 (the atom influencing the 1-2 bond in a bond-order sense) * m -* gamma -* lambda3 (1/distance units) +* :math:`\gamma` +* :math:`\lambda_3` (1/distance units) * c * d -* costheta0 (can be a value < -1 or > 1) +* :math:`\cos\theta_0` (can be a value < -1 or > 1) * n -* beta -* lambda2 (1/distance units) +* :math:`\beta` +* :math:`\lambda_2` (1/distance units) * B (energy units) * R (distance units) * D (distance units) -* lambda1 (1/distance units) +* :math:`\lambda_1` (1/distance units) * A (energy units) -The n, beta, lambda2, B, lambda1, and A parameters are only used for -two-body interactions. The m, gamma, lambda3, c, d, and costheta0 +The n, :math:`\beta`, :math:`\lambda_2`, B, :math:`\lambda_1`, and A +parameters are only used for +two-body interactions. The m, :math:`\gamma`, :math:`\lambda_3`, c, d, +and :math:`\cos\theta_0` parameters are only used for three-body interactions. The R and D parameters are used for both two-body and three-body interactions. The non-annotated parameters are unitless. The value of m must be 3 or 1. @@ -149,7 +167,8 @@ SiCC entry. The parameters used for a particular three-body interaction come from the entry with the corresponding three elements. The parameters used only for two-body interactions -(n, beta, lambda2, B, lambda1, and A) in entries whose 2nd and 3rd +(n, :math:`\beta`, :math:`\lambda_2`, B, :math:`\lambda_1`, and A) +in entries whose 2nd and 3rd element are different (e.g. SiCSi) are not used for anything and can be set to 0.0 if desired. @@ -165,16 +184,24 @@ it reduces to the form of :ref:`Albe et al. ` when beta = 1 and m = 1. Note that in the current Tersoff implementation in LAMMPS, m must be specified as either 3 or 1. Tersoff used a slightly different but equivalent form for alloys, which we will refer to as Tersoff\_2 -potential :ref:`(Tersoff\_2) `. The *tersoff/table* style implements +potential :ref:`(Tersoff\_2) `. +The *tersoff/table* style implements Tersoff\_2 parameterization only. LAMMPS parameter values for Tersoff\_2 can be obtained as follows: -gamma\_ijk = omega\_ik, lambda3 = 0 and the value of +:math:`\gamma_{ijk} = \omega_{ik}`, :math:`\lambda_3 = 0` and the value of m has no effect. The parameters for species i and j can be calculated using the Tersoff\_2 mixing rules: -.. image:: Eqs/pair_tersoff_2.jpg - :align: center +.. math:: + + \lambda_1^{i,j} & = \frac{1}{2}(\lambda_1^i + \lambda_1^j)\\ + \lambda_2^{i,j} & = \frac{1}{2}(\lambda_2^i + \lambda_2^j)\\ + A_{i,j} & = (A_{i}A_{j})^{1/2}\\ + B_{i,j} & = \chi_{ij}(B_{i}B_{j})^{1/2}\\ + R_{i,j} & = (R_{i}R_{j})^{1/2}\\ + S_{i,j} & = (S_{i}S_{j})^{1/2} + Tersoff\_2 parameters R and S must be converted to the LAMMPS parameters R and D (R is different in both forms), using the following diff --git a/doc/src/pair_tersoff_mod.rst b/doc/src/pair_tersoff_mod.rst index dbe0b4d95b..94cc9300ed 100644 --- a/doc/src/pair_tersoff_mod.rst +++ b/doc/src/pair_tersoff_mod.rst @@ -49,21 +49,40 @@ potential :ref:`(Tersoff\_1) `, :ref:`(Tersoff\_2) ` wit modified cutoff function and angular-dependent term, giving the energy E of a system of atoms as -.. image:: Eqs/pair_tersoff_mod.jpg - :align: center - -where f\_R is a two-body term and f\_A includes three-body interactions. +.. math:: + + E & = \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\ + V_{ij} & = f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) \right] \\ + f_C(r) & = \left\{ \begin{array} {r@{\quad:\quad}l} + 1 & r < R - D \\ + \frac{1}{2} - \frac{9}{16} \sin \left( \frac{\pi}{2} \frac{r-R}{D} \right) - \frac{1}{16} \sin \left( \frac{3\pi}{2} \frac{r-R}{D} \right) & + R-D < r < R + D \\ + 0 & r > R + D + \end{array} \right. \\ + f_R(r) & = A \exp (-\lambda_1 r) \\ + f_A(r) & = -B \exp (-\lambda_2 r) \\ + b_{ij} & = \left( 1 + {\zeta_{ij}}^\eta \right)^{-\frac{1}{2n}} \\ + \zeta_{ij} & = \sum_{k \neq i,j} f_C(r_{ik}) g(\theta_{ijk}) + \exp \left[ \alpha (r_{ij} - r_{ik})^\beta \right] \\ + g(\theta) & = c_1 + g_o(\theta) g_a(\theta) \\ + g_o(\theta) & = \frac{c_2 (h - \cos \theta)^2}{c_3 + (h - \cos \theta)^2} \\ + g_a(\theta) & = 1 + c_4 \exp \left[ -c_5 (h - \cos \theta)^2 \right] \\ + + +where :math:`f_R` is a two-body term and :math:`f_A` includes three-body interactions. The summations in the formula are over all neighbors J and K of atom I within a cutoff distance = R + D. The *tersoff/mod/c* style differs from *tersoff/mod* only in the formulation of the V\_ij term, where it contains an additional c0 term. -.. image:: Eqs/pair_tersoff_mod_c.jpg - :align: center +.. math:: + + V_{ij} & = f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) + c_0 \right] + -The modified cutoff function f\_C proposed by :ref:`(Murty) ` and +The modified cutoff function :math:`f_C` proposed by :ref:`(Murty) ` and having a continuous second-order differential is employed. The -angular-dependent term g(theta) was modified to increase the +angular-dependent term :math:`g(\theta)` was modified to increase the flexibility of the potential. The *tersoff/mod* potential is fitted to both the elastic constants @@ -105,30 +124,30 @@ not blank or comments (starting with #) define parameters for a triplet of elements. The parameters in a single entry correspond to coefficients in the formulae above: -element 1 (the center atom in a 3-body interaction) -element 2 (the atom bonded to the center atom) -element 3 (the atom influencing the 1-2 bond in a bond-order sense) -beta -alpha -h -eta -beta\_ters = 1 (dummy parameter) -lambda2 (1/distance units) -B (energy units) -R (distance units) -D (distance units) -lambda1 (1/distance units) -A (energy units) -n -c1 -c2 -c3 -c4 -c5 -c0 (energy units, tersoff/mod/c only):ul - -The n, eta, lambda2, B, lambda1, and A parameters are only used for -two-body interactions. The beta, alpha, c1, c2, c3, c4, c5, h +* element 1 (the center atom in a 3-body interaction) +* element 2 (the atom bonded to the center atom) +* element 3 (the atom influencing the 1-2 bond in a bond-order sense) +* :math:`\beta` +* :math:`\alpha` +* h +* :math:`\eta` +* :math:`\beta_{ters}` = 1 (dummy parameter) +* :math:`\lambda_2` (1/distance units) +* B (energy units) +* R (distance units) +* D (distance units) +* :math:`\lambda_1` (1/distance units) +* A (energy units) +* n +* c1 +* c2 +* c3 +* c4 +* c5 +* c0 (energy units, tersoff/mod/c only):ul + +The n, :math:`\eta`, :math:`\lambda_2`, B, :math:`\lambda_1`, and A parameters are only used for +two-body interactions. The :math:`\beta`, :math:`\alpha`, c1, c2, c3, c4, c5, h parameters are only used for three-body interactions. The R and D parameters are used for both two-body and three-body interactions. The c0 term applies to *tersoff/mod/c* only. The non-annotated diff --git a/doc/src/pair_tersoff_zbl.rst b/doc/src/pair_tersoff_zbl.rst index 2ad3be9d7d..e60de64f28 100644 --- a/doc/src/pair_tersoff_zbl.rst +++ b/doc/src/pair_tersoff_zbl.rst @@ -38,26 +38,53 @@ based on a Coulomb potential and the Ziegler-Biersack-Littmark universal screening function :ref:`(ZBL) `, giving the energy E of a system of atoms as -.. image:: Eqs/pair_tersoff_zbl.jpg - :align: center - -The f\_F term is a fermi-like function used to smoothly connect the ZBL +.. math:: + + E & = \frac{1}{2} \sum_i \sum_{j \neq i} V_{ij} \\ + V_{ij} & = (1 - f_F(r_{ij})) V^{ZBL}_{ij} + f_F(r_{ij}) V^{Tersoff}_{ij} \\ + f_F(r_{ij}) & = \frac{1}{1 + e^{-A_F(r_{ij} - r_C)}}\\ + \\ + \\ + V^{ZBL}_{ij} & = \frac{1}{4\pi\epsilon_0} \frac{Z_1 Z_2 \,e^2}{r_{ij}} \phi(r_{ij}/a) \\ + a & = \frac{0.8854\,a_0}{Z_{1}^{0.23} + Z_{2}^{0.23}}\\ + \phi(x) & = 0.1818e^{-3.2x} + 0.5099e^{-0.9423x} + 0.2802e^{-0.4029x} + 0.02817e^{-0.2016x}\\ + \\ + \\ + V^{Tersoff}_{ij} & = f_C(r_{ij}) \left[ f_R(r_{ij}) + b_{ij} f_A(r_{ij}) \right] \\ + f_C(r) & = \left\{ \begin{array} {r@{\quad:\quad}l} + 1 & r < R - D \\ + \frac{1}{2} - \frac{1}{2} \sin \left( \frac{\pi}{2} \frac{r-R}{D} \right) & + R-D < r < R + D \\ + 0 & r > R + D + \end{array} \right. \\ + f_R(r) & = A \exp (-\lambda_1 r) \\ + f_A(r) & = -B \exp (-\lambda_2 r) \\ + b_{ij} & = \left( 1 + \beta^n {\zeta_{ij}}^n \right)^{-\frac{1}{2n}} \\ + \zeta_{ij} & = \sum_{k \neq i,j} f_C(r_{ik}) g(\theta_{ijk}) + \exp \left[ {\lambda_3}^m (r_{ij} - r_{ik})^m \right] \\ + g(\theta) & = \gamma_{ijk} \left( 1 + \frac{c^2}{d^2} - + \frac{c^2}{\left[ d^2 + (\cos \theta - \cos \theta_0)^2\right]} \right) + + +The :math:`f_F` term is a fermi-like function used to smoothly connect the ZBL repulsive potential with the Tersoff potential. There are 2 -parameters used to adjust it: A\_F and r\_C. A\_F controls how "sharp" -the transition is between the two, and r\_C is essentially the cutoff +parameters used to adjust it: :math:`A_F` and :math:`r_C`. :math:`A_F` +controls how "sharp" +the transition is between the two, and :math:`r_C` is essentially the cutoff for the ZBL potential. For the ZBL portion, there are two terms. The first is the Coulomb repulsive term, with Z1, Z2 as the number of protons in each nucleus, -e as the electron charge (1 for metal and real units) and epsilon0 as -the permittivity of vacuum. The second part is the ZBL universal +e as the electron charge (1 for metal and real units) and :math:`\epsilon_0` +as the permittivity of vacuum. The second part is the ZBL universal screening function, with a0 being the Bohr radius (typically 0.529 Angstroms), and the remainder of the coefficients provided by the original paper. This screening function should be applicable to most systems. However, it is only accurate for small separations (i.e. less than 1 Angstrom). -For the Tersoff portion, f\_R is a two-body term and f\_A includes +For the Tersoff portion, :math:`f_R` is a two-body term and :math:`f_A` +includes three-body interactions. The summations in the formula are over all neighbors J and K of atom I within a cutoff distance = R + D. @@ -102,29 +129,32 @@ in the formula above: * element 2 (the atom bonded to the center atom) * element 3 (the atom influencing the 1-2 bond in a bond-order sense) * m -* gamma -* lambda3 (1/distance units) +* :math:`\gamma` +* :math:`\lambda_3` (1/distance units) * c * d -* costheta0 (can be a value < -1 or > 1) +* :math:`\cos\theta_0` (can be a value < -1 or > 1) * n -* beta -* lambda2 (1/distance units) +* :math:`\beta` +* :math:`\lambda_2` (1/distance units) * B (energy units) * R (distance units) * D (distance units) -* lambda1 (1/distance units) +* :math:`\lambda_1` (1/distance units) * A (energy units) -* Z\_i -* Z\_j +* :math:`Z_i` +* :math:`Z_j` * ZBLcut (distance units) * ZBLexpscale (1/distance units) -The n, beta, lambda2, B, lambda1, and A parameters are only used for -two-body interactions. The m, gamma, lambda3, c, d, and costheta0 +The n, :math:`\beta`, :math:`\lambda_2`, B, :math:`\lambda_1`, and A +parameters are only used for +two-body interactions. The m, :math:`\gamma`, :math:`\lambda_3`, c, d, +and :math:`\cos\theta_0` parameters are only used for three-body interactions. The R and D parameters are used for both two-body and three-body interactions. The -Z\_i,Z\_j, ZBLcut, ZBLexpscale parameters are used in the ZBL repulsive +:math:`Z_i`, :math:`Z_j`, ZBLcut, ZBLexpscale parameters are used in the +ZBL repulsive portion of the potential and in the Fermi-like function. The non-annotated parameters are unitless. The value of m must be 3 or 1. @@ -153,7 +183,8 @@ SiCC entry. The parameters used for a particular three-body interaction come from the entry with the corresponding three elements. The parameters used only for two-body interactions -(n, beta, lambda2, B, lambda1, and A) in entries whose 2nd and 3rd +(n, :math:`\beta`, :math:`\lambda_2`, B, :math:`\lambda_1`, and A) +in entries whose 2nd and 3rd element are different (e.g. SiCSi) are not used for anything and can be set to 0.0 if desired. @@ -172,12 +203,19 @@ different but equivalent form for alloys, which we will refer to as Tersoff\_2 potential :ref:`(Tersoff\_2) `. LAMMPS parameter values for Tersoff\_2 can be obtained as follows: -gamma = omega\_ijk, lambda3 = 0 and the value of +:math:`\gamma = \omega_{ijk}`, :math:`\lambda_3 = 0` and the value of m has no effect. The parameters for species i and j can be calculated using the Tersoff\_2 mixing rules: -.. image:: Eqs/pair_tersoff_2.jpg - :align: center +.. math:: + + \lambda_1^{i,j} & = \frac{1}{2}(\lambda_1^i + \lambda_1^j)\\ + \lambda_2^{i,j} & = \frac{1}{2}(\lambda_2^i + \lambda_2^j)\\ + A_{i,j} & = (A_{i}A_{j})^{1/2}\\ + B_{i,j} & = \chi_{ij}(B_{i}B_{j})^{1/2}\\ + R_{i,j} & = (R_{i}R_{j})^{1/2}\\ + S_{i,j} & = (S_{i}S_{j})^{1/2}\\ + Tersoff\_2 parameters R and S must be converted to the LAMMPS parameters R and D (R is different in both forms), using the following diff --git a/doc/src/pair_ufm.rst b/doc/src/pair_ufm.rst index 3bb4e83a0e..c8a7e42743 100644 --- a/doc/src/pair_ufm.rst +++ b/doc/src/pair_ufm.rst @@ -42,10 +42,16 @@ Description Style *ufm* computes pairwise interactions using the Uhlenbeck-Ford model (UFM) potential :ref:`(Paula Leite2016) ` which is given by -.. image:: Eqs/pair_ufm.jpg - :align: center +.. math:: -where rc is the cutoff, sigma is a distance-scale and epsilon is an energy-scale, i.e., a product of Boltzmann constant kB, temperature T and the Uhlenbeck-Ford p-parameter which is responsible + E & = -\varepsilon\, \ln{\left[1-\exp{\left(-r^{2}/\sigma^{2}\right)}\right]} \qquad r < r_c \\ + \varepsilon & = p\,k_B\,T + + +where :math:`r_c` is the cutoff, :math:`\sigma` is a distance-scale and +:math:`\epsilon` is an energy-scale, i.e., a product of Boltzmann constant +:math:`k_B`, temperature *T* and the Uhlenbeck-Ford p-parameter which +is responsible to control the softness of the interactions :ref:`(Paula Leite2017) `. This model is useful as a reference system for fluid-phase free-energy calculations :ref:`(Paula Leite2016) `. @@ -55,8 +61,8 @@ 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: -* epsilon (energy units) -* sigma (distance units) +* :math:`\epsilon` (energy units) +* :math:`\sigma` (distance units) * cutoff (distance units) The last coefficient is optional. If not specified, the global *ufm* @@ -76,7 +82,13 @@ of a run: .. note:: - The thermodynamic integration procedure can be performed with this potential using :doc:`fix adapt `. This command will rescale the force on each atom by varying a scale variable, which always starts with value 1.0. The syntax is the same described above, however, changing epsilon to scale. A detailed explanation of how to use this command and perform nonequilibrium thermodynamic integration in LAMMPS is given in the paper by :ref:`(Freitas) `. + The thermodynamic integration procedure can be performed with this + potential using :doc:`fix adapt `. This command will + rescale the force on each atom by varying a scale variable, which + always starts with value 1.0. The syntax is the same described above, + however, changing epsilon to scale. A detailed explanation of how to + use this command and perform nonequilibrium thermodynamic integration + in LAMMPS is given in the paper by :ref:`(Freitas) `. ---------- diff --git a/doc/src/pair_vashishta.rst b/doc/src/pair_vashishta.rst index de29985f56..2dde0482be 100644 --- a/doc/src/pair_vashishta.rst +++ b/doc/src/pair_vashishta.rst @@ -63,16 +63,21 @@ including SiO2 :ref:`Vashishta1990 `, SiC The potential for the energy U of a system of atoms is -.. image:: Eqs/pair_vashishta.jpg - :align: center +.. math:: + + U & = \sum_i^N \sum_{j > i}^N U_{ij}^{(2)} (r_{ij}) + \sum_i^N \sum_{j \neq i}^N \sum_{k > j, k \neq i}^N U_{ijk}^{(3)} (r_{ij}, r_{ik}, \theta_{ijk}) \\ + U_{ij}^{(2)} (r) & = \frac{H_{ij}}{r^{\eta_{ij}}} + \frac{Z_i Z_j}{r}\exp(-r/\lambda_{1,ij}) - \frac{D_{ij}}{r^4}\exp(-r/\lambda_{4,ij}) - \frac{W_{ij}}{r^6}, r < r_{c,{ij}} \\ + U_{ijk}^{(3)}(r_{ij},r_{ik},\theta_{ijk}) & = B_{ijk} \frac{\left[ \cos \theta_{ijk} - \cos \theta_{0ijk} \right]^2} {1+C_{ijk}\left[ \cos \theta_{ijk} - \cos \theta_{0ijk} \right]^2} \times \\ + & \exp \left( \frac{\gamma_{ij}}{r_{ij} - r_{0,ij}} \right) \exp \left( \frac{\gamma_{ik}}{r_{ik} - r_{0,ik}} \right), r_{ij} < r_{0,ij}, r_{ik} < r_{0,ik} + where we follow the notation used in :ref:`Branicio2009 `. -U2 is a two-body term and U3 is a three-body term. The +:math:`U^2` is a two-body term and U3 is a three-body term. The summation over two-body terms is over all neighbors J within -a cutoff distance = *rc*\ . The twobody terms are shifted and +a cutoff distance = :math:`r_c`. The twobody terms are shifted and tilted by a linear function so that the energy and force are -both zero at *rc*\ . The summation over three-body terms -is over all neighbors J and K within a cut-off distance = *r0*\ , +both zero at :math:`r_c`. The summation over three-body terms +is over all neighbors *i* and *k* within a cut-off distance :math:`= r_0`, where the exponential screening function becomes zero. The *vashishta* style computes these formulas analytically. The @@ -126,20 +131,20 @@ and three-body coefficients in the formulae above: * element 1 (the center atom in a 3-body interaction) * element 2 * element 3 -* H (energy units) -* eta -* Zi (electron charge units) -* Zj (electron charge units) -* lambda1 (distance units) -* D (energy units) -* lambda4 (distance units) -* W (energy units) -* rc (distance units) -* B (energy units) -* gamma -* r0 (distance units) -* C -* costheta0 +* *H* (energy units) +* :math:`\eta` +* :math:`Z_i` (electron charge units) +* :math:`Z_j` (electron charge units) +* :math:`\lambda_1` (distance units) +* *D* (energy units) +* :math:`\lambda_4` (distance units) +* *W* (energy units) +* :math:`r_c` (distance units) +* *B* (energy units) +* :math:`\gamma` +* :math:`r_0` (distance units) +* *C* +* :math:`\cos\theta_0` The non-annotated parameters are unitless. The Vashishta potential file must contain entries for all the elements listed in the @@ -159,12 +164,14 @@ unambiguous, general, and simple to code, LAMMPS uses a slightly confusing method for specifying parameters. All parameters are divided into two classes: two-body and three-body. Two-body and three-body parameters are handled differently, as described below. -The two-body parameters are H, eta, lambda1, D, lambda4, W, rc, gamma, -and r0. They appear in the above formulae with two subscripts. The -parameters Zi and Zj are also classified as two-body parameters, even -though they only have 1 subscript. The three-body parameters are B, -C, costheta0. They appear in the above formulae with three -subscripts. Two-body and three-body parameters are handled +The two-body parameters are *H*\ , :math:`\eta`, :math:`\lambda_1`, +*D*\ , :math:`\lambda_4`, *W*, :math:`r_c`, :math:`\gamma`, +and :math:`r_0`. They appear in the above formulae with two subscripts. +The parameters :math:`Z_i` and :math:`Z_j` are also classified +as two-body parameters, even +though they only have 1 subscript. The three-body parameters are *B*\ , +*C*\ , :math:`\cos\theta_0`. They appear in the above formulae with +three subscripts. Two-body and three-body parameters are handled differently, as described below. The first element in each entry is the center atom in a three-body @@ -184,7 +191,8 @@ ensure that these values are equal. Two-body parameters appearing in entries where the 2nd and 3rd elements are different are stored but never used. It is good practice to enter zero for these values. Note that the three-body function U3 above contains the two-body parameters -gamma and r0. So U3 for a central C atom bonded to an Si atom and a +:math:`\gamma` and :math:`r_0`. So U3 for a central C atom bonded to +an Si atom and a second C atom will take three-body parameters from the CSiC entry, but two-body parameters from the CCC and CSiSi entries. diff --git a/doc/src/pair_yukawa.rst b/doc/src/pair_yukawa.rst index c3a8e9fc71..b7cb6818d2 100644 --- a/doc/src/pair_yukawa.rst +++ b/doc/src/pair_yukawa.rst @@ -38,10 +38,12 @@ Description Style *yukawa* computes pairwise interactions with the formula -.. image:: Eqs/pair_yukawa.jpg - :align: center +.. math:: -Rc is the cutoff. + E = A \frac{e^{- \kappa r}}{r} \qquad r < r_c + + +:math:`r_c` is the cutoff. The following coefficients must be defined for each pair of atoms types via the :doc:`pair_coeff ` command as in the examples diff --git a/doc/src/pair_yukawa_colloid.rst b/doc/src/pair_yukawa_colloid.rst index 76bf010fb9..2c337bdb94 100644 --- a/doc/src/pair_yukawa_colloid.rst +++ b/doc/src/pair_yukawa_colloid.rst @@ -35,11 +35,13 @@ Description Style *yukawa/colloid* computes pairwise interactions with the formula -.. image:: Eqs/pair_yukawa_colloid.jpg - :align: center +.. math:: -where Ri and Rj are the radii of the two particles and Rc is the -cutoff. + E = \frac{A}{\kappa} e^{- \kappa (r - (r_i + r_j))} \qquad r < r_c + + +where :math:`r_i` and :math:`r_j` are the radii of the two particles +and :math:`r_c` is the cutoff. In contrast to :doc:`pair_style yukawa `, this functional form arises from the Coulombic interaction between two colloid @@ -49,7 +51,7 @@ theory. :doc:`Pair\_style yukawa ` is a screened Coulombic potential between two point-charges and uses no such approximation. This potential applies to nearby particle pairs for which the Derjagin -approximation holds, meaning h << Ri + Rj, where h is the +approximation holds, meaning :math:`h << r_i + r_j`, where *h* is the surface-to-surface separation of the two particles. When used in combination with :doc:`pair_style colloid `, @@ -72,17 +74,17 @@ used in :doc:`pair_style yukawa `. For low surface potentials, i.e. less than about 25 mV, A can be written as: -.. parsed-literal:: +.. math:: - A = 2 \* PI \* R\*eps\*eps0 \* kappa \* psi\^2 + A = 2 \pi R\varepsilon\varepsilon_0 \kappa \psi^2 where -* R = colloid radius (distance units) -* eps0 = permittivity of free space (charge\^2/energy/distance units) -* eps = relative permittivity of fluid medium (dimensionless) -* kappa = inverse screening length (1/distance units) -* psi = surface potential (energy/charge units) +* *R* = colloid radius (distance units) +* :math:`\varepsilon_0` = permittivity of free space (charge\^2/energy/distance units) +* :math:`\varepsilon` = relative permittivity of fluid medium (dimensionless) +* :math:`\kappa` = inverse screening length (1/distance units) +* :math:`\psi` = surface potential (energy/charge units) The last coefficient is optional. If not specified, the global yukawa/colloid cutoff is used. diff --git a/doc/src/pair_zbl.rst b/doc/src/pair_zbl.rst index 8e34341172..bffcf9fbda 100644 --- a/doc/src/pair_zbl.rst +++ b/doc/src/pair_zbl.rst @@ -43,12 +43,16 @@ that ramps the energy, force, and curvature smoothly to zero between an inner and outer cutoff. The potential energy due to a pair of atoms at a distance r\_ij is given by: -.. image:: Eqs/pair_zbl.jpg - :align: center +.. math:: -where e is the electron charge, epsilon\_0 is the electrical -permittivity of vacuum, and Z\_i and Z\_j are the nuclear charges of the -two atoms. The switching function S(r) is identical to that used by + E^{ZBL}_{ij} & = \frac{1}{4\pi\epsilon_0} \frac{Z_i Z_j \,e^2}{r_{ij}} \phi(r_{ij}/a)+ S(r_{ij})\\ + a & = \frac{0.46850}{Z_{i}^{0.23} + Z_{j}^{0.23}}\\ + \phi(x) & = 0.18175e^{-3.19980x} + 0.50986e^{-0.94229x} + 0.28022e^{-0.40290x} + 0.02817e^{-0.20162x}\\ + +where *e* is the electron charge, :math:`\epsilon_0` is the electrical +permittivity of vacuum, and :math:`Z_i` and :math:`Z_j` are the nuclear +charges of the +two atoms. The switching function :math:`S(r)` is identical to that used by :doc:`pair_style lj/gromacs `. Here, the inner and outer cutoff are the same for all pairs of atom types. @@ -56,16 +60,17 @@ 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 LAMMPS data file. -* Z\_i (atomic number for first atom type, e.g. 13.0 for aluminum) +* :math:`Z_i` (atomic number for first atom type, e.g. 13.0 for aluminum) -* Z\_j (ditto for second atom type) +* :math:`Z_j` (ditto for second atom type) -The values of Z\_i and Z\_j are normally equal to the atomic +The values of :math:`Z_i` and :math:`Z_j` are normally equal to the atomic numbers of the two atom types. Thus, the user may optionally -specify only the coefficients for each I==I pair, and rely +specify only the coefficients for each :math:`i==i` pair, and rely on the obvious mixing rule for cross interactions (see below). -Note that when I==I it is required that Z\_i == Z\_j. When used -with :doc:`hybrid/overlay ` and pairs are assigned +Note that when :math:`i==i` it is required that :math:`Z_i == Z_j`. +When used with :doc:`hybrid/overlay ` and pairs are +assigned to more than one sub-style, the mixing rule is not used and each pair of types interacting with the ZBL sub-style must be included in a pair\_coeff command. @@ -108,9 +113,11 @@ instructions on how to use the accelerated styles effectively. **Mixing, shift, table, tail correction, restart, rRESPA info**\ : -For atom type pairs I,J and I != J, the Z\_i and Z\_j coefficients -can be mixed by taking Z\_i and Z\_j from the values specified for -I == I and J == J cases. When used +For atom type pairs *i,j* and :math:`i \neq i`, the :math:`Z_i` and +:math:`Z_j` coefficients +can be mixed by taking :math:`Z_i` and :math:`Z_j` from the values +specified for +:math:`i == i` and :math:`j == j` cases. When used with :doc:`hybrid/overlay ` and pairs are assigned to more than one sub-style, the mixing rule is not used and each pair of types interacting with the ZBL sub-style diff --git a/doc/src/set.rst b/doc/src/set.rst index 8214ce8ba9..c633587b25 100644 --- a/doc/src/set.rst +++ b/doc/src/set.rst @@ -235,7 +235,7 @@ that a particular atom is changed or not changed, regardless of how many processors are being used. This keyword does not allow use of an atom-style variable. -Keywords *type/ratio* and *type/subset" also set the atom type for a +Keywords *type/ratio* and *type/subset* also set the atom type for a fraction of the selected atoms. The actual number of atoms changed will be exactly the requested number. For *type/ratio* the specified fraction (0 <= *fraction* <= 1) determines the number. For diff --git a/examples/USER/plumed/log.27Nov18.peptide-plumed.g++.1 b/examples/USER/plumed/log.4Feb20.peptide-plumed.g++.1 similarity index 82% rename from examples/USER/plumed/log.27Nov18.peptide-plumed.g++.1 rename to examples/USER/plumed/log.4Feb20.peptide-plumed.g++.1 index eb67b96fce..fb77bee0cc 100644 --- a/examples/USER/plumed/log.27Nov18.peptide-plumed.g++.1 +++ b/examples/USER/plumed/log.4Feb20.peptide-plumed.g++.1 @@ -1,5 +1,4 @@ -LAMMPS (27 Nov 2018) - using 1 OpenMP thread(s) per MPI task +LAMMPS (4 Feb 2020) # Solvated 5-mer peptide units real @@ -39,6 +38,8 @@ read_data data.peptide 7 = max # of 1-3 neighbors 14 = max # of 1-4 neighbors 18 = max # of special neighbors + special bonds CPU = 0.000809431 secs + read_data CPU = 0.0102327 secs neighbor 2.0 bin neigh_modify delay 5 @@ -66,6 +67,7 @@ fix 4 all shake 0.0001 10 100 b 4 6 8 10 12 14 18 a 31 6 = # of size 3 clusters 3 = # of size 4 clusters 640 = # of frozen angles + find clusters CPU = 0.000631809 secs #dump 1 colvar custom 1 dump.colvar.lammpstrj id xu yu zu fx fy fz #dump_modify 1 sort id @@ -77,13 +79,13 @@ variable pe equal pe run 101 PPPM initialization ... - using 12-bit tables for long-range coulomb (src/kspace.cpp:321) + using 12-bit tables for long-range coulomb (src/kspace.cpp:332) G vector (1/distance) = 0.268725 grid = 15 15 15 stencil order = 5 estimated absolute RMS force accuracy = 0.0228209 estimated relative force accuracy = 6.87243e-05 - using double precision FFTs + using double precision FFTW3 3d grid and FFT values/proc = 10648 3375 Neighbor list info ... update every 1 steps, delay 5 steps, check yes @@ -106,7 +108,7 @@ SHAKE stats (type/ave/delta) on step 0 14 0.96 0 18 0.957206 4.37979e-05 31 104.519 0.00396029 -Per MPI rank memory allocation (min/avg/max) = 18.74 | 18.74 | 18.74 Mbytes +Per MPI rank memory allocation (min/avg/max) = 19.07 | 19.07 | 19.07 Mbytes Step Temp TotEng PotEng KinEng E_pair E_bond f_2 0 282.10052 -5237.458 -6372.3766 1134.9186 -6442.768 16.557152 0 10 276.9783 -5234.3057 -6348.6171 1114.3114 -6421.6171 17.024361 0.47785504 @@ -129,22 +131,22 @@ SHAKE stats (type/ave/delta) on step 100 31 104.52 0.000760401 100 270.40648 -5234.9604 -6322.8327 1087.8723 -6417.73 19.666404 0.0094784372 101 270.99811 -5235.8295 -6326.082 1090.2525 -6418.8974 17.285816 0.086681332 -Loop time of 2.73445 on 1 procs for 101 steps with 2004 atoms +Loop time of 2.69839 on 1 procs for 101 steps with 2004 atoms -Performance: 6.383 ns/day, 3.760 hours/ns, 36.936 timesteps/s -99.7% CPU use with 1 MPI tasks x 1 OpenMP threads +Performance: 6.468 ns/day, 3.711 hours/ns, 37.430 timesteps/s +99.7% CPU use with 1 MPI tasks x no OpenMP threads MPI task timing breakdown: Section | min time | avg time | max time |%varavg| %total --------------------------------------------------------------- -Pair | 2.2617 | 2.2617 | 2.2617 | 0.0 | 82.71 -Bond | 0.0044148 | 0.0044148 | 0.0044148 | 0.0 | 0.16 -Kspace | 0.17883 | 0.17883 | 0.17883 | 0.0 | 6.54 -Neigh | 0.23945 | 0.23945 | 0.23945 | 0.0 | 8.76 -Comm | 0.011672 | 0.011672 | 0.011672 | 0.0 | 0.43 -Output | 0.00028348 | 0.00028348 | 0.00028348 | 0.0 | 0.01 -Modify | 0.0365 | 0.0365 | 0.0365 | 0.0 | 1.33 -Other | | 0.001611 | | | 0.06 +Pair | 2.2853 | 2.2853 | 2.2853 | 0.0 | 84.69 +Bond | 0.0065637 | 0.0065637 | 0.0065637 | 0.0 | 0.24 +Kspace | 0.14949 | 0.14949 | 0.14949 | 0.0 | 5.54 +Neigh | 0.1938 | 0.1938 | 0.1938 | 0.0 | 7.18 +Comm | 0.0096588 | 0.0096588 | 0.0096588 | 0.0 | 0.36 +Output | 0.00039172 | 0.00039172 | 0.00039172 | 0.0 | 0.01 +Modify | 0.050643 | 0.050643 | 0.050643 | 0.0 | 1.88 +Other | | 0.00258 | | | 0.10 Nlocal: 2004 ave 2004 max 2004 min Histogram: 1 0 0 0 0 0 0 0 0 0 diff --git a/examples/USER/plumed/log.27Nov18.peptide-plumed.g++.4 b/examples/USER/plumed/log.4Feb20.peptide-plumed.g++.4 similarity index 82% rename from examples/USER/plumed/log.27Nov18.peptide-plumed.g++.4 rename to examples/USER/plumed/log.4Feb20.peptide-plumed.g++.4 index 72b851c2ff..1bbbed6cd8 100644 --- a/examples/USER/plumed/log.27Nov18.peptide-plumed.g++.4 +++ b/examples/USER/plumed/log.4Feb20.peptide-plumed.g++.4 @@ -1,5 +1,4 @@ -LAMMPS (27 Nov 2018) - using 1 OpenMP thread(s) per MPI task +LAMMPS (4 Feb 2020) # Solvated 5-mer peptide units real @@ -39,6 +38,8 @@ read_data data.peptide 7 = max # of 1-3 neighbors 14 = max # of 1-4 neighbors 18 = max # of special neighbors + special bonds CPU = 0.00095129 secs + read_data CPU = 0.0199838 secs neighbor 2.0 bin neigh_modify delay 5 @@ -66,6 +67,7 @@ fix 4 all shake 0.0001 10 100 b 4 6 8 10 12 14 18 a 31 6 = # of size 3 clusters 3 = # of size 4 clusters 640 = # of frozen angles + find clusters CPU = 0.000829935 secs #dump 1 colvar custom 1 dump.colvar.lammpstrj id xu yu zu fx fy fz #dump_modify 1 sort id @@ -77,13 +79,13 @@ variable pe equal pe run 101 PPPM initialization ... - using 12-bit tables for long-range coulomb (src/kspace.cpp:321) + using 12-bit tables for long-range coulomb (src/kspace.cpp:332) G vector (1/distance) = 0.268725 grid = 15 15 15 stencil order = 5 estimated absolute RMS force accuracy = 0.0228209 estimated relative force accuracy = 6.87243e-05 - using double precision FFTs + using double precision FFTW3 3d grid and FFT values/proc = 4312 960 Neighbor list info ... update every 1 steps, delay 5 steps, check yes @@ -106,7 +108,7 @@ SHAKE stats (type/ave/delta) on step 0 14 0.96 0 18 0.957206 4.37979e-05 31 104.519 0.00396029 -Per MPI rank memory allocation (min/avg/max) = 15.66 | 15.87 | 16.06 Mbytes +Per MPI rank memory allocation (min/avg/max) = 16.02 | 16.23 | 16.42 Mbytes Step Temp TotEng PotEng KinEng E_pair E_bond f_2 0 282.10052 -5237.458 -6372.3766 1134.9186 -6442.768 16.557152 0 10 276.9783 -5234.3057 -6348.6171 1114.3114 -6421.6171 17.024361 0.47785504 @@ -129,22 +131,22 @@ SHAKE stats (type/ave/delta) on step 100 31 104.52 0.000760401 100 270.40648 -5234.9604 -6322.8327 1087.8723 -6417.73 19.666404 0.0094784372 101 270.99811 -5235.8295 -6326.082 1090.2525 -6418.8974 17.285816 0.086681332 -Loop time of 0.812799 on 4 procs for 101 steps with 2004 atoms +Loop time of 0.873215 on 4 procs for 101 steps with 2004 atoms -Performance: 21.472 ns/day, 1.118 hours/ns, 124.262 timesteps/s -97.5% CPU use with 4 MPI tasks x 1 OpenMP threads +Performance: 19.987 ns/day, 1.201 hours/ns, 115.664 timesteps/s +92.5% 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.57957 | 0.59988 | 0.62504 | 2.6 | 73.80 -Bond | 0.00080013 | 0.0017412 | 0.0028315 | 2.1 | 0.21 -Kspace | 0.075724 | 0.10008 | 0.12023 | 6.4 | 12.31 -Neigh | 0.067733 | 0.067947 | 0.068168 | 0.1 | 8.36 -Comm | 0.01375 | 0.014175 | 0.014681 | 0.3 | 1.74 -Output | 0.00025511 | 0.00051183 | 0.001277 | 0.0 | 0.06 -Modify | 0.026406 | 0.026436 | 0.026462 | 0.0 | 3.25 -Other | | 0.002027 | | | 0.25 +Pair | 0.58191 | 0.61681 | 0.66371 | 3.8 | 70.64 +Bond | 0.00099587 | 0.0023546 | 0.0041356 | 2.8 | 0.27 +Kspace | 0.096162 | 0.14486 | 0.18119 | 8.1 | 16.59 +Neigh | 0.059843 | 0.059864 | 0.059876 | 0.0 | 6.86 +Comm | 0.013623 | 0.01368 | 0.013723 | 0.0 | 1.57 +Output | 0.00031137 | 0.0010193 | 0.0024326 | 2.6 | 0.12 +Modify | 0.031552 | 0.031697 | 0.032087 | 0.1 | 3.63 +Other | | 0.002938 | | | 0.34 Nlocal: 501 ave 512 max 492 min Histogram: 1 0 0 1 0 1 0 0 0 1 diff --git a/examples/USER/plumed/reference/p.log b/examples/USER/plumed/reference/p.log index 79d0bbd84c..29d99077e4 100644 --- a/examples/USER/plumed/reference/p.log +++ b/examples/USER/plumed/reference/p.log @@ -1,12 +1,12 @@ PLUMED: PLUMED is starting -PLUMED: Version: 2.4.2 (git: Unknown) compiled on Jul 11 2018 at 19:09:03 -PLUMED: Please cite this paper when using PLUMED [1] +PLUMED: Version: 2.6.0 (git: Unknown) compiled on Feb 13 2020 at 15:49:44 +PLUMED: Please cite these papers when using PLUMED [1][2] PLUMED: For further information see the PLUMED web page at http://www.plumed.org -PLUMED: Root: /Users/gareth/MD_code/lammps-permanent/lammps/lib/plumed/plumed2-2.4.2/ -PLUMED: For installed feature, see /Users/gareth/MD_code/lammps-permanent/lammps/lib/plumed/plumed2-2.4.2//src/config/config.txt +PLUMED: Root: /home/akohlmey/compile/lammps/build-gcc/plumed_build-prefix/lib/plumed +PLUMED: For installed feature, see /home/akohlmey/compile/lammps/build-gcc/plumed_build-prefix/lib/plumed/src/config/config.txt PLUMED: Molecular dynamics engine: LAMMPS PLUMED: Precision of reals: 8 -PLUMED: Running over 1 node +PLUMED: Running over 4 nodes PLUMED: Number of threads: 1 PLUMED: Cache line size: 512 PLUMED: Number of atoms: 2004 @@ -14,13 +14,13 @@ PLUMED: File suffix: PLUMED: FILE: plumed.dat PLUMED: Action UNITS PLUMED: with label @0 -PLUMED: length: A -PLUMED: energy: kcal/mol +PLUMED: length: A = 0.1 nm +PLUMED: energy: kcal/mol = 4.184 kj/mol PLUMED: time: ps PLUMED: charge: e PLUMED: mass: amu PLUMED: using physical units -PLUMED: inside PLUMED, Boltzmann constant is 0.001987 +PLUMED: inside PLUMED, Boltzmann constant is 0.0019872 PLUMED: Action DISTANCE PLUMED: with label dd PLUMED: between atoms 45 48 @@ -44,14 +44,15 @@ PLUMED: Timestep: 0.002000 PLUMED: KbT has not been set by the MD engine PLUMED: It should be set by hand where needed PLUMED: Relevant bibliography: -PLUMED: [1] Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014) +PLUMED: [1] The PLUMED consortium, Nat. Methods 16, 670 (2019) +PLUMED: [2] Tribello, Bonomi, Branduardi, Camilloni, and Bussi, Comput. Phys. Commun. 185, 604 (2014) PLUMED: Please read and cite where appropriate! PLUMED: Finished setup PLUMED: Cycles Total Average Minumum Maximum -PLUMED: 1 0.020354 0.020354 0.020354 0.020354 -PLUMED: 1 Prepare dependencies 102 0.000256 0.000003 0.000001 0.000006 -PLUMED: 2 Sharing data 102 0.010002 0.000098 0.000078 0.000546 -PLUMED: 3 Waiting for data 102 0.001398 0.000014 0.000011 0.000072 -PLUMED: 4 Calculating (forward loop) 102 0.001797 0.000018 0.000013 0.000058 -PLUMED: 5 Applying (backward loop) 102 0.002666 0.000026 0.000022 0.000062 -PLUMED: 6 Update 102 0.001126 0.000011 0.000007 0.000055 +PLUMED: 1 0.010018 0.010018 0.010018 0.010018 +PLUMED: 1 Prepare dependencies 102 0.000241 0.000002 0.000001 0.000003 +PLUMED: 2 Sharing data 102 0.002132 0.000021 0.000006 0.000151 +PLUMED: 3 Waiting for data 102 0.001640 0.000016 0.000008 0.000067 +PLUMED: 4 Calculating (forward loop) 102 0.000825 0.000008 0.000005 0.000013 +PLUMED: 5 Applying (backward loop) 102 0.000522 0.000005 0.000002 0.000015 +PLUMED: 6 Update 102 0.001755 0.000017 0.000011 0.000067 diff --git a/lib/gpu/lal_lj_tip4p_long.cpp b/lib/gpu/lal_lj_tip4p_long.cpp index d44edc8cbd..f60f162d7b 100644 --- a/lib/gpu/lal_lj_tip4p_long.cpp +++ b/lib/gpu/lal_lj_tip4p_long.cpp @@ -74,11 +74,11 @@ int LJTIP4PLongT::init(const int ntypes, // If atom type constants fit in shared memory use fast kernel int lj_types=ntypes; shared_types=false; -// int max_shared_types=this->device->max_shared_types(); -// if (lj_types<=max_shared_types && this->_block_size>=max_shared_types) { -// lj_types=max_shared_types; -// shared_types=true; -// } + int max_shared_types=this->device->max_shared_types(); + if (lj_types<=max_shared_types && this->_block_size>=max_shared_types) { + lj_types=max_shared_types; + shared_types=true; + } _lj_types=lj_types; // Allocate a host write buffer for data initialization @@ -202,7 +202,6 @@ void LJTIP4PLongT::loop(const bool _eflag, const bool _vflag) { GX=static_cast(ceil(static_cast(this->ans->inum())/ (BX/this->_threads_per_atom))); - this->k_pair.set_size(GX,BX); if (vflag) { this->ansO.resize_ib(ainum*3); } else { @@ -210,13 +209,25 @@ void LJTIP4PLongT::loop(const bool _eflag, const bool _vflag) { } this->ansO.zero(); this->device->gpu->sync(); - this->k_pair.run(&this->atom->x, &lj1, &lj3, &_lj_types, &sp_lj, + if(shared_types) { + this->k_pair_fast.set_size(GX,BX); + this->k_pair_fast.run(&this->atom->x, &lj1, &lj3, &_lj_types, &sp_lj, &this->nbor->dev_nbor, &this->_nbor_data->begin(), &this->ans->force, &this->ans->engv, &eflag, &vflag, &ainum, &nbor_pitch, &this->_threads_per_atom, &hneight, &m, &TypeO, &TypeH, &alpha, &this->atom->q, &cutsq, &_qqrd2e, &_g_ewald, &cut_coulsq, &cut_coulsqplus, &this->ansO); + } else { + this->k_pair.set_size(GX,BX); + this->k_pair.run(&this->atom->x, &lj1, &lj3, &_lj_types, &sp_lj, + &this->nbor->dev_nbor, &this->_nbor_data->begin(), + &this->ans->force, &this->ans->engv, &eflag, &vflag, + &ainum, &nbor_pitch, &this->_threads_per_atom, + &hneight, &m, &TypeO, &TypeH, &alpha, + &this->atom->q, &cutsq, &_qqrd2e, &_g_ewald, + &cut_coulsq, &cut_coulsqplus, &this->ansO); + } GX=static_cast(ceil(static_cast(this->ans->inum())/BX)); this->k_pair_distrib.set_size(GX,BX); this->k_pair_distrib.run(&this->atom->x, &this->ans->force, &this->ans->engv, diff --git a/lib/gpu/lal_lj_tip4p_long.cu b/lib/gpu/lal_lj_tip4p_long.cu index 147c460795..c101196433 100644 --- a/lib/gpu/lal_lj_tip4p_long.cu +++ b/lib/gpu/lal_lj_tip4p_long.cu @@ -572,4 +572,328 @@ __kernel void k_lj_tip4p_long(const __global numtyp4 *restrict x_, } // if ii } -__kernel void k_lj_tip4p_long_fast() {} +__kernel void k_lj_tip4p_long_fast(const __global numtyp4 *restrict x_, + const __global numtyp4 *restrict lj1_in, + const __global numtyp4 *restrict lj3_in, + const int lj_types, + const __global numtyp *restrict sp_lj_in, + const __global int * dev_nbor, + const __global int * dev_packed, + __global acctyp4 *restrict ans, + __global acctyp *restrict engv, + const int eflag, const int vflag, const int inum, + const int nbor_pitch, const int t_per_atom, + __global int *restrict hneigh, + __global numtyp4 *restrict m, + const int typeO, const int typeH, + const numtyp alpha, + const __global numtyp *restrict q_, + const __global numtyp *restrict cutsq, + const numtyp qqrd2e, const numtyp g_ewald, + const numtyp cut_coulsq, const numtyp cut_coulsqplus, + __global acctyp4 *restrict ansO) { + int tid, ii, offset; + atom_info(t_per_atom,ii,tid,offset); + + const numtyp eq_zero = 1e-6; + + __local numtyp4 lj1[MAX_SHARED_TYPES*MAX_SHARED_TYPES]; + __local numtyp4 lj3[MAX_SHARED_TYPES*MAX_SHARED_TYPES]; + __local numtyp sp_lj[8]; + if (tid<8) + sp_lj[tid]=sp_lj_in[tid]; + if (tid0) + lj3[tid]=lj3_in[tid]; + } + acctyp energy = (acctyp)0; + acctyp e_coul = (acctyp)0; + acctyp4 f, fO; + f.x=(acctyp)0; f.y=(acctyp)0; f.z=(acctyp)0; + fO.x=(acctyp)0; fO.y=(acctyp)0; fO.z=(acctyp)0; + acctyp virial[6],vO[6]; + for (int i=0; i<6; i++) { + virial[i]=(acctyp)0; + vO[i]=(acctyp)0; + } + + __syncthreads(); + if (ii= inum) { + non_local_oxy = 1; + } + } + + for ( ; nbor0) { + numtyp e = r6inv * (lj3[mtype].x*r6inv-lj3[mtype].y); + energy += factor_lj * (e - lj3[mtype].z); + } + if (vflag>0) { + virial[0] += delx*delx*forcelj; + virial[1] += dely*dely*forcelj; + virial[2] += delz*delz*forcelj; + virial[3] += delx*dely*forcelj; + virial[4] += delx*delz*forcelj; + virial[5] += dely*delz*forcelj; + } + } // if LJ + + if (rsq < cut_coulsqplus) { //cut_coulsqplus + int jH1, jH2, jO; + numtyp qj; fetch(qj,j,q_tex); + numtyp4 x2 = jx; + if(itype == typeO || jtype == typeO) { + if (jtype == typeO) { + jO = j; + jH1 = hneigh[j*4 ]; + jH2 = hneigh[j*4+1]; + x2 = m[j]; + } + delx = x1.x-x2.x; + dely = x1.y-x2.y; + delz = x1.z-x2.z; + rsq = delx*delx+dely*dely+delz*delz; + } + if (rsq < cut_coulsq) { + numtyp r2inv = ucl_recip(rsq); + numtyp r = ucl_rsqrt(r2inv); + numtyp grij = g_ewald * r; + numtyp expm2 = ucl_exp(-grij*grij); + numtyp t = ucl_recip((numtyp)1.0 + EWALD_P*grij); + numtyp _erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; + + numtyp prefactor = qj; + prefactor *= qqrd2e*qtmp/r; + numtyp force_coul = r2inv*prefactor * (_erfc + EWALD_F*grij*expm2 - factor_coul); + + if (itype == typeH) { + f.x += delx * force_coul; + f.y += dely * force_coul; + f.z += delz * force_coul; + f.w += 0; + } else { + fO.x += delx * force_coul; + fO.y += dely * force_coul; + fO.z += delz * force_coul; + fO.w += 0; + } + if (eflag>0) { + e_coul += prefactor*(_erfc-factor_coul); + } + if (vflag>0) { + acctyp4 fd; + fd.x = delx*force_coul; + fd.y = dely*force_coul; + fd.z = delz*force_coul; + if (itype == typeH) { + if (jtype == typeH) { + virial[0] += delx*fd.x; + virial[1] += dely*fd.y; + virial[2] += delz*fd.z; + virial[3] += delx*fd.y; + virial[4] += delx*fd.z; + virial[5] += dely*fd.z; + } else { + numtyp cO = 1 - alpha, cH = 0.5*alpha; + numtyp4 vdj; + numtyp4 xjH1; fetch4(xjH1,jH1,pos_tex); + numtyp4 xjH2; fetch4(xjH2,jH2,pos_tex); + numtyp4 xjO; fetch4(xjO,jO,pos_tex); + vdj.x = xjO.x*cO + xjH1.x*cH + xjH2.x*cH; + vdj.y = xjO.y*cO + xjH1.y*cH + xjH2.y*cH; + vdj.z = xjO.z*cO + xjH1.z*cH + xjH2.z*cH; + //vdj.w = vdj.w; + virial[0] += (ix.x - vdj.x)*fd.x; + virial[1] += (ix.y - vdj.y)*fd.y; + virial[2] += (ix.z - vdj.z)*fd.z; + virial[3] += (ix.x - vdj.x)*fd.y; + virial[4] += (ix.x - vdj.x)*fd.z; + virial[5] += (ix.y - vdj.y)*fd.z; + } + } else { + numtyp cO = 1 - alpha, cH = 0.5*alpha; + numtyp4 vdi, vdj; + numtyp4 xH1; fetch4(xH1,iH1,pos_tex); + numtyp4 xH2; fetch4(xH2,iH2,pos_tex); + numtyp4 xO; fetch4(xO,iO,pos_tex); + vdi.x = xO.x*cO + xH1.x*cH + xH2.x*cH; + vdi.y = xO.y*cO + xH1.y*cH + xH2.y*cH; + vdi.z = xO.z*cO + xH1.z*cH + xH2.z*cH; + //vdi.w = vdi.w; + if (jtype != typeH) { + numtyp4 xjH1; fetch4(xjH1,jH1,pos_tex); + numtyp4 xjH2; fetch4(xjH2,jH2,pos_tex); + numtyp4 xjO; fetch4(xjO,jO,pos_tex); + vdj.x = xjO.x*cO + xjH1.x*cH + xjH2.x*cH; + vdj.y = xjO.y*cO + xjH1.y*cH + xjH2.y*cH; + vdj.z = xjO.z*cO + xjH1.z*cH + xjH2.z*cH; + //vdj.w = vdj.w; + } else vdj = jx; + vO[0] += 0.5*(vdi.x - vdj.x)*fd.x; + vO[1] += 0.5*(vdi.y - vdj.y)*fd.y; + vO[2] += 0.5*(vdi.z - vdj.z)*fd.z; + vO[3] += 0.5*(vdi.x - vdj.x)*fd.y; + vO[4] += 0.5*(vdi.x - vdj.x)*fd.z; + vO[5] += 0.5*(vdi.y - vdj.y)*fd.z; + } + } + } + if (non_local_oxy == 1) { + if (iO == j) { + x2 = ix; + qj = qtmp; + } + numtyp4 x1m = m[iO]; + delx = x1m.x-x2.x; + dely = x1m.y-x2.y; + delz = x1m.z-x2.z; + rsq = delx*delx+dely*dely+delz*delz; + if (rsq < cut_coulsq) { + numtyp r2inv = ucl_recip(rsq); + numtyp r = ucl_rsqrt(r2inv); + numtyp grij = g_ewald * r; + numtyp expm2 = ucl_exp(-grij*grij); + numtyp t = ucl_recip((numtyp)1.0 + EWALD_P*grij); + numtyp _erfc = t * (A1+t*(A2+t*(A3+t*(A4+t*A5)))) * expm2; + + numtyp prefactor = qj; + prefactor *= qqrd2e*x1m.w/r; + numtyp force_coul = r2inv*prefactor * (_erfc + EWALD_F*grij*expm2 - factor_coul); + + numtyp cO = 1 - alpha, cH = 0.5*alpha; + numtyp4 fd; + fd.x = delx * force_coul * cH; + fd.y = dely * force_coul * cH; + fd.z = delz * force_coul * cH; + + f.x += fd.x; + f.y += fd.y; + f.z += fd.z; + + if (eflag>0) { + e_coul += prefactor*(_erfc-factor_coul) * (acctyp)0.5 * alpha; + } + if (vflag>0) { + numtyp4 xH1; fetch4(xH1,iH1,pos_tex); + numtyp4 xH2; fetch4(xH2,iH2,pos_tex); + numtyp4 xO; fetch4(xO,iO,pos_tex); + + virial[0] += ((xO.x*cO + xH1.x*cH + xH2.x*cH) - x2.x) * fd.x; + virial[1] += ((xO.y*cO + xH1.y*cH + xH2.y*cH) - x2.y) * fd.y; + virial[2] += ((xO.z*cO + xH1.z*cH + xH2.z*cH) - x2.z) * fd.z; + virial[3] += ((xO.x*cO + xH1.x*cH + xH2.x*cH) - x2.x) * fd.y; + virial[4] += ((xO.x*cO + xH1.x*cH + xH2.x*cH) - x2.x) * fd.z; + virial[5] += ((xO.y*cO + xH1.y*cH + xH2.y*cH) - x2.y) * fd.z; + } + } + } + } // if cut_coulsqplus + } // for nbor + if (t_per_atom>1) { +#if (ARCH < 300) + __local acctyp red_acc[6][BLOCK_PAIR]; + red_acc[0][tid]=fO.x; + red_acc[1][tid]=fO.y; + red_acc[2][tid]=fO.z; + red_acc[3][tid]=fO.w; + for (unsigned int s=t_per_atom/2; s>0; s>>=1) { + if (offset < s) { + for (int r=0; r<4; r++) + red_acc[r][tid] += red_acc[r][tid+s]; + } + } + fO.x=red_acc[0][tid]; + fO.y=red_acc[1][tid]; + fO.z=red_acc[2][tid]; + fO.w=red_acc[3][tid]; + if (vflag>0) { + for (int r=0; r<6; r++) red_acc[r][tid]=vO[r]; + for (unsigned int s=t_per_atom/2; s>0; s>>=1) { + if (offset < s) { + for (int r=0; r<6; r++) + red_acc[r][tid] += red_acc[r][tid+s]; + } + } + for (int r=0; r<6; r++) vO[r]=red_acc[r][tid]; + } +#else + for (unsigned int s=t_per_atom/2; s>0; s>>=1) { + fO.x += shfl_xor(fO.x, s, t_per_atom); + fO.y += shfl_xor(fO.y, s, t_per_atom); + fO.z += shfl_xor(fO.z, s, t_per_atom); + fO.w += shfl_xor(fO.w, s, t_per_atom); + } + if (vflag>0) { + for (unsigned int s=t_per_atom/2; s>0; s>>=1) { + for (int r=0; r<6; r++) + vO[r] += shfl_xor(vO[r], s, t_per_atom); + } + } +#endif + } + if(offset == 0) { + ansO[i] = fO; + if (vflag>0) { + ansO[inum + i].x = vO[0]; + ansO[inum + i].y = vO[1]; + ansO[inum + i].z = vO[2]; + ansO[inum*2 + i].x = vO[3]; + ansO[inum*2 + i].y = vO[4]; + ansO[inum*2 + i].z = vO[5]; + } + } + store_answers_q(f,energy,e_coul,virial,ii,inum,tid,t_per_atom,offset,eflag, + vflag,ans,engv); + } // if ii +} diff --git a/lib/plumed/Install.py b/lib/plumed/Install.py index 668e681b3c..b6b00d1511 100644 --- a/lib/plumed/Install.py +++ b/lib/plumed/Install.py @@ -17,7 +17,7 @@ parser = ArgumentParser(prog='Install.py', # settings -version = "2.5.3" +version = "2.6.0" mode = "static" # help message @@ -46,6 +46,8 @@ checksums = { \ '2.5.1' : 'c2a7b519e32197a120cdf47e0f194f81', \ '2.5.2' : 'bd2f18346c788eb54e1e52f4f6acf41a', \ '2.5.3' : 'de30d6e7c2dcc0973298e24a6da24286', \ + '2.5.4' : 'f31b7d16a4be2e30aa7d5c19c3d37853', \ + '2.6.0' : '204d2edae58d9b10ba3ad460cad64191', \ } # parse and process arguments diff --git a/lib/qmmm/Makefile.gfortran b/lib/qmmm/Makefile.gfortran index 717922b4b6..9b43d2eaa0 100644 --- a/lib/qmmm/Makefile.gfortran +++ b/lib/qmmm/Makefile.gfortran @@ -7,9 +7,9 @@ EXTRAMAKE = Makefile.lammps.empty QETOPDIR=$(HOME)/compile/espresso # import compiler settings from Quantum ESPRESSO -sinclude $(QETOPDIR)/make.sys +sinclude $(QETOPDIR)/make.inc -# FLAGS for c++ OpenMPI 1.8.8 or later when QE was compiled with GNU Fortran 4.x +# FLAGS for c++ OpenMPI 3.x.x or later when QE was compiled with GNU Fortran 6.x or 7.x MPICXX=mpicxx MPICXXFLAGS=-DOMPI_SKIP_MPICXX=1 -O2 -Wall -g -fPIC\ -I../../src -I$(QETOPDIR)/COUPLE/include @@ -24,13 +24,21 @@ $(QETOPDIR)/Modules/libqemod.a # part 2: lo-level libraries for all of Q-E LIBOBJS = \ $(QETOPDIR)/FFTXlib/libqefft.a \ +$(QETOPDIR)/dft-d3/libdftd3qe.a \ +$(QETOPDIR)/KS_Solvers/PPCG/libppcg.a \ +$(QETOPDIR)/KS_Solvers/CG/libcg.a \ +$(QETOPDIR)/KS_Solvers/Davidson/libdavid.a \ +$(QETOPDIR)/UtilXlib/libutil.a \ $(QETOPDIR)/LAXlib/libqela.a \ $(QETOPDIR)/clib/clib.a \ $(QETOPDIR)/iotk/src/libiotk.a +# foxlibs + +LIBS += -L${QETOPDIR}/FoX/lib -lFoX_dom -lFoX_sax -lFoX_wxml -lFoX_common -lFoX_utils -lFoX_fsys -L${LAPACK_LIB} -L${BLAS_LIB} -llapack -lblas # part 3: add-on libraries and main library for LAMMPS sinclude ../../src/Makefile.package -LAMMPSCFG = openmpi-omp +LAMMPSCFG = mpi LAMMPSLIB = ../../src/liblammps_$(LAMMPSCFG).a # part 4: local QM/MM library and progams diff --git a/lib/qmmm/Makefile.ifort b/lib/qmmm/Makefile.ifort index d03e67b8a0..1a4f4b600e 100644 --- a/lib/qmmm/Makefile.ifort +++ b/lib/qmmm/Makefile.ifort @@ -3,17 +3,20 @@ # this file will be copied to Makefile.lammps EXTRAMAKE = Makefile.lammps.empty -# top level directory of Quantum ESPRESSO 5.4.1 or later +# top level directory of Quantum ESPRESSO 6.4 or later QETOPDIR=$(HOME)/compile/espresso # import compiler settings from Quantum ESPRESSO -sinclude $(QETOPDIR)/make.sys +sinclude $(QETOPDIR)/make.inc # FLAGS for c++ with IntelMPI when QE was compiled with Intel Fortran -MPICXX=icpc -MPICXXFLAGS=-DOMPI_SKIP_MPICXX=1 -O2 -Wall -g -fPIC\ - -I../../src -I$(QETOPDIR)/COUPLE/include -I${INTELMPI_HOME}/include64 -MPILIBS=-openmp -L${INTELMPI_HOME}/lib64 -lz -lifcore -L$(I_MPI_ROOT)/lib64 -lmpi -lmpiif + +MPICXX=mpiicpc +MPICXXFLAGS=-DOMPI_SKIP_MPICXX=1 -DFC_ABORT_ARG -O2 -Wall -g -fPIC -I${INTEL_HOME}/include -I${INTELMPI_HOME}/include64 \ + -I../../src -I$(QETOPDIR)/COUPLE/include -I$(QETOPDIR)/LAXlib -I$(QETOPDIR)/UtilXlib -I$(QETOPDIR)/FoX/finclude -tbb + +MPILIBS=-qopenmp -L${INTELMPI_HOME}/lib64 -lz -lifcore -lifport -L$(I_MPI_ROOT)/lib64 -lmpi -lmpifort + # location of required libraries # part 1: hi-level libraries for building pw.x @@ -24,13 +27,20 @@ $(QETOPDIR)/Modules/libqemod.a # part 2: lo-level libraries for all of Q-E LIBOBJS = \ $(QETOPDIR)/FFTXlib/libqefft.a \ +$(QETOPDIR)/dft-d3/libdftd3qe.a \ +$(QETOPDIR)/KS_Solvers/PPCG/libppcg.a \ +$(QETOPDIR)/KS_Solvers/CG/libcg.a \ +$(QETOPDIR)/KS_Solvers/Davidson/libdavid.a \ +$(QETOPDIR)/UtilXlib/libutil.a \ $(QETOPDIR)/LAXlib/libqela.a \ $(QETOPDIR)/clib/clib.a \ $(QETOPDIR)/iotk/src/libiotk.a +# foxlibs +LIBS += -L${QETOPDIR}/FoX/lib -lFoX_dom -lFoX_sax -lFoX_wxml -lFoX_common -lFoX_utils -lFoX_fsys -mkl -ltbbmalloc # part 3: add-on libraries and main library for LAMMPS sinclude ../../src/Makefile.package -LAMMPSCFG = galileo-omp +LAMMPSCFG =intel_cpu LAMMPSLIB = ../../src/liblammps_$(LAMMPSCFG).a # part 4: local QM/MM library and progams diff --git a/lib/qmmm/README b/lib/qmmm/README index 2746c9e86e..9046cf59de 100644 --- a/lib/qmmm/README +++ b/lib/qmmm/README @@ -4,7 +4,7 @@ Axel Kohlmeyer, akohlmey@gmail.com Temple University, Philadelphia and ICTP, Trieste with contributions by -Carlo Cavazzoni & Mariella Ippolito +Mariella Ippolito & Carlo Cavazzoni Cineca, Italy This library provides the basic glue code to combine LAMMPS with the @@ -32,9 +32,7 @@ and 4 manually, as outlined below. WARNING: This is experimental code under developement and is provided at this early stage to encourage others to write interfaces to other QM codes. Please test *very* carefully before using this software for -production calculations. At the time of the last update of this README -(July 2016) you have to download a QE snapshot (revision 12611) from -the QE subversion repository. +production calculations. At this point, both mechanical and multipole based electrostatic coupling have been successfully tested on a cluster of water @@ -70,12 +68,7 @@ to confirm that the classical part of the code is set up correctly. Step 3) Build a standalone pw.x executable in the Quantum ESPRESSO directory -and also make the "couple" target. At the time of this writing -(July 2016) you have to download a QE snapshot (revision 12611) -from the SVN repository, since no official release with the -completed QM/MM support code has been made available yet. The current -plan is to have a usable QM/MM interface released with the next -Quantum ESPRESSO release version 6.0. Building the standalone pw.x +and also make the "couple" target. Building the standalone pw.x binary is also needed to confirm that corresponding QM input is working correctly and to run test calculations on QM atoms only. diff --git a/src/GPU/pair_born_coul_long_gpu.cpp b/src/GPU/pair_born_coul_long_gpu.cpp index 39d34420a8..1b548edab6 100644 --- a/src/GPU/pair_born_coul_long_gpu.cpp +++ b/src/GPU/pair_born_coul_long_gpu.cpp @@ -177,6 +177,10 @@ void PairBornCoulLongGPU::init_style() error->all(FLERR,"Pair style requires a KSpace style"); g_ewald = force->kspace->g_ewald; + // setup force tables + + if (ncoultablebits) init_tables(cut_coul,cut_respa); + int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; diff --git a/src/GPU/pair_buck_coul_long_gpu.cpp b/src/GPU/pair_buck_coul_long_gpu.cpp index e30230d5a0..7e59562ebf 100644 --- a/src/GPU/pair_buck_coul_long_gpu.cpp +++ b/src/GPU/pair_buck_coul_long_gpu.cpp @@ -173,6 +173,10 @@ void PairBuckCoulLongGPU::init_style() error->all(FLERR,"Pair style requires a KSpace style"); g_ewald = force->kspace->g_ewald; + // setup force tables + + if (ncoultablebits) init_tables(cut_coul,cut_respa); + int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; diff --git a/src/GPU/pair_lj_class2_coul_long_gpu.cpp b/src/GPU/pair_lj_class2_coul_long_gpu.cpp index 4ee776b4ff..96ba4e0a09 100644 --- a/src/GPU/pair_lj_class2_coul_long_gpu.cpp +++ b/src/GPU/pair_lj_class2_coul_long_gpu.cpp @@ -170,6 +170,10 @@ void PairLJClass2CoulLongGPU::init_style() error->all(FLERR,"Pair style requires a KSpace style"); g_ewald = force->kspace->g_ewald; + // setup force tables + + if (ncoultablebits) init_tables(cut_coul,cut_respa); + int maxspecial=0; if (atom->molecular) maxspecial=atom->maxspecial; diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index e0b1c92821..540389f599 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -85,6 +85,8 @@ action comm_kokkos.cpp action comm_kokkos.h action comm_tiled_kokkos.cpp action comm_tiled_kokkos.h +action compute_orientorder_atom_kokkos.cpp +action compute_orientorder_atom_kokkos.h action compute_temp_kokkos.cpp action compute_temp_kokkos.h action dihedral_charmm_kokkos.cpp dihedral_charmm.cpp diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp new file mode 100644 index 0000000000..7915e4faa9 --- /dev/null +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp @@ -0,0 +1,698 @@ +/* ---------------------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Stan Moore (SNL) +------------------------------------------------------------------------- */ + +#include "compute_orientorder_atom_kokkos.h" +#include +#include +#include +#include "atom_kokkos.h" +#include "update.h" +#include "modify.h" +#include "neighbor_kokkos.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "force.h" +#include "pair.h" +#include "comm.h" +#include "memory_kokkos.h" +#include "error.h" +#include "math_const.h" +#include "atom_masks.h" +#include "kokkos.h" + +using namespace LAMMPS_NS; +using namespace MathConst; +using namespace std; + +#ifdef DBL_EPSILON + #define MY_EPSILON (10.0*DBL_EPSILON) +#else + #define MY_EPSILON (10.0*2.220446049250313e-16) +#endif + +#define QEPSILON 1.0e-6 + +/* ---------------------------------------------------------------------- */ + +template +ComputeOrientOrderAtomKokkos::ComputeOrientOrderAtomKokkos(LAMMPS *lmp, int narg, char **arg) : + ComputeOrientOrderAtom(lmp, narg, arg) +{ + atomKK = (AtomKokkos *) atom; + execution_space = ExecutionSpaceFromDevice::space; + datamask_read = EMPTY_MASK; + datamask_modify = EMPTY_MASK; +} + +/* ---------------------------------------------------------------------- */ + +template +ComputeOrientOrderAtomKokkos::~ComputeOrientOrderAtomKokkos() +{ + if (copymode) return; + + memoryKK->destroy_kokkos(k_qnarray,qnarray); +} + +/* ---------------------------------------------------------------------- */ + +template +void ComputeOrientOrderAtomKokkos::init() +{ + ComputeOrientOrderAtom::init(); + + d_qlist = t_sna_1i("orientorder/atom:qlist",nqlist); + auto h_qlist = Kokkos::create_mirror_view(d_qlist); + for (int i = 0; i < nqlist; i++) + h_qlist(i) = qlist[i]; + Kokkos::deep_copy(d_qlist,h_qlist); + + // need an occasional full neighbor list + + // irequest = neigh request made by parent class + + int irequest = neighbor->nrequest - 1; + + neighbor->requests[irequest]-> + kokkos_host = Kokkos::Impl::is_same::value && + !Kokkos::Impl::is_same::value; + neighbor->requests[irequest]-> + kokkos_device = Kokkos::Impl::is_same::value; +} + +/* ---------------------------------------------------------------------- */ + +template +struct FindMaxNumNeighs { + typedef DeviceType device_type; + NeighListKokkos k_list; + + FindMaxNumNeighs(NeighListKokkos* nl): k_list(*nl) {} + ~FindMaxNumNeighs() {k_list.copymode = 1;} + + KOKKOS_INLINE_FUNCTION + void operator() (const int& ii, int& maxneigh) const { + const int i = k_list.d_ilist[ii]; + const int num_neighs = k_list.d_numneigh[i]; + if (maxneigh < num_neighs) maxneigh = num_neighs; + } +}; + +/* ---------------------------------------------------------------------- */ + +template +void ComputeOrientOrderAtomKokkos::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // invoke full neighbor list (will copy or build if necessary) + + neighbor->build_one(list); + + inum = list->inum; + NeighListKokkos* k_list = static_cast*>(list); + d_numneigh = k_list->d_numneigh; + d_neighbors = k_list->d_neighbors; + d_ilist = k_list->d_ilist; + + maxneigh = 0; + Kokkos::parallel_reduce("ComputeOrientOrderAtomKokkos::find_max_neighs",inum, FindMaxNumNeighs(k_list), Kokkos::Experimental::Max(maxneigh)); + + // grow order parameter array if necessary + + if (atom->nmax > nmax) { + memoryKK->destroy_kokkos(k_qnarray,qnarray); + nmax = atom->nmax; + memoryKK->create_kokkos(k_qnarray,qnarray,nmax,ncol,"orientorder/atom:qnarray"); + array_atom = qnarray; + d_qnarray = k_qnarray.template view(); + + d_qnm = t_sna_3c("orientorder/atom:qnm",nmax,nqlist,2*qmax+1); + d_ncount = t_sna_1i("orientorder/atom:ncount",nmax); + + // insure distsq and nearest arrays are long enough + + if (maxneigh > d_distsq.extent(1)) { + d_distsq = t_sna_2d_lr("orientorder/atom:distsq",nmax,maxneigh); + d_nearest = t_sna_2i_lr("orientorder/atom:nearest",nmax,maxneigh); + d_rlist = t_sna_3d_lr("orientorder/atom:rlist",nmax,maxneigh,3); + + d_distsq_um = d_distsq; + d_rlist_um = d_rlist; + d_nearest_um = d_nearest; + } + } + + // compute order parameter for each atom in group + // use full neighbor list to count atoms less than cutoff + + atomKK->sync(execution_space,X_MASK|MASK_MASK); + x = atomKK->k_x.view(); + mask = atomKK->k_mask.view(); + + Kokkos::deep_copy(d_qnm,{0.0,0.0}); + + int vector_length = 1; + int team_size = 1; + int team_size_max = Kokkos::TeamPolicy::team_size_max(*this); +#ifdef KOKKOS_ENABLE_CUDA + team_size = 32;//maxneigh; + if (team_size*vector_length > team_size_max) + team_size = team_size_max/vector_length; +#endif + + copymode = 1; + + //Neigh + typename Kokkos::TeamPolicy policy_neigh(inum,team_size,vector_length); + Kokkos::parallel_for("ComputeOrientOrderAtomNeigh",policy_neigh,*this); + + //Select3 + typename Kokkos::RangePolicy policy_select3(0,inum); + Kokkos::parallel_for("ComputeOrientOrderAtomSelect3",policy_select3,*this); + + //BOOP1 + typename Kokkos::TeamPolicy policy_boop1(((inum+team_size-1)/team_size)*maxneigh,team_size,vector_length); + Kokkos::parallel_for("ComputeOrientOrderAtomBOOP1",policy_boop1,*this); + + //BOOP2 + typename Kokkos::RangePolicy policy_boop2(0,inum); + Kokkos::parallel_for("ComputeOrientOrderAtomBOOP2",policy_boop2,*this); + + copymode = 0; + + k_qnarray.template modify(); + k_qnarray.template sync(); +} + +/* ---------------------------------------------------------------------- */ + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomNeigh,const typename Kokkos::TeamPolicy::member_type& team) const +{ + const int ii = team.league_rank(); + const int i = d_ilist[ii]; + if (mask[i] & groupbit) { + const X_FLOAT xtmp = x(i,0); + const X_FLOAT ytmp = x(i,1); + const X_FLOAT ztmp = x(i,2); + const int jnum = d_numneigh[i]; + + // loop over list of all neighbors within force cutoff + // distsq[] = distance sq to each + // rlist[] = distance vector to each + // nearest[] = atom indices of neighbors + + int ncount = 0; + Kokkos::parallel_reduce(Kokkos::TeamThreadRange(team,jnum), + [&] (const int jj, int& count) { + Kokkos::single(Kokkos::PerThread(team), [&] (){ + int j = d_neighbors(i,jj); + j &= NEIGHMASK; + const F_FLOAT delx = x(j,0) - xtmp; + const F_FLOAT dely = x(j,1) - ytmp; + const F_FLOAT delz = x(j,2) - ztmp; + const F_FLOAT rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) + count++; + }); + },ncount); + + d_ncount(ii) = ncount; + + if (team.team_rank() == 0) + Kokkos::parallel_scan(Kokkos::ThreadVectorRange(team,jnum), + [&] (const int jj, int& offset, bool final) { + int j = d_neighbors(i,jj); + j &= NEIGHMASK; + const F_FLOAT delx = x(j,0) - xtmp; + const F_FLOAT dely = x(j,1) - ytmp; + const F_FLOAT delz = x(j,2) - ztmp; + const F_FLOAT rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + if (final) { + d_distsq(ii,offset) = rsq; + d_rlist(ii,offset,0) = delx; + d_rlist(ii,offset,1) = dely; + d_rlist(ii,offset,2) = delz; + d_nearest(ii,offset) = j; + } + offset++; + } + }); + } +} + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomSelect3,const int& ii) const { + + const int i = d_ilist[ii]; + const int ncount = d_ncount(ii); + + // if not nnn neighbors, order parameter = 0; + + if ((ncount == 0) || (ncount < nnn)) { + for (int jj = 0; jj < ncol; jj++) + d_qnarray(i,jj) = 0.0; + return; + } + + // if nnn > 0, use only nearest nnn neighbors + + if (nnn > 0) { + select3(nnn, ncount, ii); + d_ncount(ii) = nnn; + } +} + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomBOOP1,const typename Kokkos::TeamPolicy::member_type& team) const { + + // Extract the atom number + int ii = team.team_rank() + team.team_size() * (team.league_rank() % ((inum+team.team_size()-1)/team.team_size())); + if (ii >= inum) return; + + // Extract the neighbor number + const int jj = team.league_rank() / ((inum+team.team_size()-1)/team.team_size()); + const int ncount = d_ncount(ii); + if (jj >= ncount) return; + + // if not nnn neighbors, order parameter = 0; + + if ((ncount == 0) || (ncount < nnn)) + return; + + calc_boop1(ncount, ii, jj); +} + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomBOOP2,const int& ii) const { + const int i = d_ilist[ii]; + const int ncount = d_ncount(ii); + calc_boop2(ncount, ii); +} + + +/* ---------------------------------------------------------------------- + select3 routine from Numerical Recipes (slightly modified) + find k smallest values in array of length n + sort auxiliary arrays at same time +------------------------------------------------------------------------- */ + +// Use no-op do while to create single statement + +#define SWAP(view,i,j) do { \ + tmp = view(i); view(i) = view(j); view(j) = tmp; \ + } while(0) + +#define ISWAP(view,i,j) do { \ + itmp = view(i); view(i) = view(j); view(j) = itmp; \ + } while(0) + +#define SWAP3(view,i,j) do { \ + tmp = view(i,0); view(i,0) = view(j,0); view(j,0) = tmp; \ + tmp = view(i,1); view(i,1) = view(j,1); view(j,1) = tmp; \ + tmp = view(i,2); view(i,2) = view(j,2); view(j,2) = tmp; \ + } while(0) + +/* ---------------------------------------------------------------------- */ + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::select3(int k, int n, int iatom) const +{ + int i,ir,j,l,mid,ia,itmp; + double a,tmp,a3[3]; + + auto arr = Kokkos::subview(d_distsq_um, iatom, Kokkos::ALL); + auto iarr = Kokkos::subview(d_nearest_um, iatom, Kokkos::ALL); + auto arr3 = Kokkos::subview(d_rlist_um, iatom, Kokkos::ALL, Kokkos::ALL); + + l = 0; + ir = n-1; + for (;;) { + if (ir <= l+1) { + if (ir == l+1 && arr[ir] < arr[l]) { + SWAP(arr,l,ir); + ISWAP(iarr,l,ir); + SWAP3(arr3,l,ir); + } + return; + } else { + mid=((l+ir+2) >> 1) - 1; + SWAP(arr,mid,l+1); + ISWAP(iarr,mid,l+1); + SWAP3(arr3,mid,l+1); + if (arr[l] > arr[ir]) { + SWAP(arr,l,ir); + ISWAP(iarr,l,ir); + SWAP3(arr3,l,ir); + } + if (arr[l+1] > arr[ir]) { + SWAP(arr,l+1,ir); + ISWAP(iarr,l+1,ir); + SWAP3(arr3,l+1,ir); + } + if (arr[l] > arr[l+1]) { + SWAP(arr,l,l+1); + ISWAP(iarr,l,l+1); + SWAP3(arr3,l,l+1); + } + i = l+1; + j = ir; + a = arr[l+1]; + ia = iarr[l+1]; + a3[0] = arr3(l+1,0); + a3[1] = arr3(l+1,1); + a3[2] = arr3(l+1,2); + for (;;) { + do i++; while (arr[i] < a); + do j--; while (arr[j] > a); + if (j < i) break; + SWAP(arr,i,j); + ISWAP(iarr,i,j); + SWAP3(arr3,i,j); + } + arr[l+1] = arr[j]; + arr[j] = a; + iarr[l+1] = iarr[j]; + iarr[j] = ia; + arr3(l+1,0) = arr3(j,0); + arr3(l+1,1) = arr3(j,1); + arr3(l+1,2) = arr3(j,2); + arr3(j,0) = a3[0]; + arr3(j,1) = a3[1]; + arr3(j,2) = a3[2]; + if (j+1 >= k) ir = j-1; + if (j+1 <= k) l = i; + } + } +} + +/* ---------------------------------------------------------------------- + calculate the bond orientational order parameters +------------------------------------------------------------------------- */ + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::calc_boop1(int ncount, int iatom, int ineigh) const +{ + const double r0 = d_rlist(iatom,ineigh,0); + const double r1 = d_rlist(iatom,ineigh,1); + const double r2 = d_rlist(iatom,ineigh,2); + const double rmag = sqrt(r0*r0 + r1*r1 + r2*r2); + if(rmag <= MY_EPSILON) { + return; + } + + const double costheta = r2 / rmag; + SNAcomplex expphi = {r0,r1}; + const double rxymag = sqrt(expphi.re*expphi.re+expphi.im*expphi.im); + if(rxymag <= MY_EPSILON) { + expphi.re = 1.0; + expphi.im = 0.0; + } else { + const double rxymaginv = 1.0/rxymag; + expphi.re *= rxymaginv; + expphi.im *= rxymaginv; + } + + for (int il = 0; il < nqlist; il++) { + const int l = d_qlist[il]; + + //d_qnm(iatom,il,l).re += polar_prefactor(l, 0, costheta); + const double polar_pf = polar_prefactor(l, 0, costheta); + Kokkos::atomic_add(&(d_qnm(iatom,il,l).re), polar_pf); + SNAcomplex expphim = {expphi.re,expphi.im}; + for(int m = 1; m <= +l; m++) { + const double prefactor = polar_prefactor(l, m, costheta); + SNAcomplex c = {prefactor * expphim.re, prefactor * expphim.im}; + //d_qnm(iatom,il,m+l).re += c.re; + //d_qnm(iatom,il,m+l).im += c.im; + Kokkos::atomic_add(&(d_qnm(iatom,il,m+l).re), c.re); + Kokkos::atomic_add(&(d_qnm(iatom,il,m+l).im), c.im); + if(m & 1) { + //d_qnm(iatom,il,-m+l).re -= c.re; + //d_qnm(iatom,il,-m+l).im += c.im; + Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).re), -c.re); + Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).im), c.im); + } else { + //d_qnm(iatom,il,-m+l).re += c.re; + //d_qnm(iatom,il,-m+l).im -= c.im; + Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).re), c.re); + Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).im), -c.im); + } + SNAcomplex tmp; + tmp.re = expphim.re*expphi.re - expphim.im*expphi.im; + tmp.im = expphim.re*expphi.im + expphim.im*expphi.re; + expphim.re = tmp.re; + expphim.im = tmp.im; + } + } +} + +/* ---------------------------------------------------------------------- + calculate the bond orientational order parameters +------------------------------------------------------------------------- */ + +template +KOKKOS_INLINE_FUNCTION +void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int iatom) const +{ + // convert sums to averages + + double facn = 1.0 / ncount; + for (int il = 0; il < nqlist; il++) { + int l = d_qlist[il]; + for(int m = 0; m < 2*l+1; m++) { + d_qnm(iatom,il,m).re *= facn; + d_qnm(iatom,il,m).im *= facn; + } + } + + // calculate Q_l + // NOTE: optional W_l_hat and components of Q_qlcomp use these stored Q_l values + + int jj = 0; + for (int il = 0; il < nqlist; il++) { + int l = d_qlist[il]; + double qnormfac = sqrt(MY_4PI/(2*l+1)); + double qm_sum = 0.0; + for(int m = 0; m < 2*l+1; m++) + qm_sum += d_qnm(iatom,il,m).re*d_qnm(iatom,il,m).re + d_qnm(iatom,il,m).im*d_qnm(iatom,il,m).im; + d_qnarray(iatom,jj++) = qnormfac * sqrt(qm_sum); + } + + // calculate W_l + + if (wlflag) { + int idxcg_count = 0; + for (int il = 0; il < nqlist; il++) { + int l = d_qlist[il]; + double wlsum = 0.0; + for(int m1 = 0; m1 < 2*l+1; m1++) { + for(int m2 = MAX(0,l-m1); m2 < MIN(2*l+1,3*l-m1+1); m2++) { + int m = m1 + m2 - l; + SNAcomplex qm1qm2; + qm1qm2.re = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).re - d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).im; + qm1qm2.im = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).im + d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).re; + wlsum += (qm1qm2.re*d_qnm(iatom,il,m).re + qm1qm2.im*d_qnm(iatom,il,m).im)*d_cglist[idxcg_count]; + idxcg_count++; + } + } + d_qnarray(iatom,jj++) = wlsum/sqrt(2.0*l+1.0); + } + } + + // calculate W_l_hat + + if (wlhatflag) { + int idxcg_count = 0; + for (int il = 0; il < nqlist; il++) { + int l = d_qlist[il]; + double wlsum = 0.0; + for(int m1 = 0; m1 < 2*l+1; m1++) { + for(int m2 = MAX(0,l-m1); m2 < MIN(2*l+1,3*l-m1+1); m2++) { + const int m = m1 + m2 - l; + SNAcomplex qm1qm2; + qm1qm2.re = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).re - d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).im; + qm1qm2.im = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).im + d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).re; + wlsum += (qm1qm2.re*d_qnm(iatom,il,m).re + qm1qm2.im*d_qnm(iatom,il,m).im)*d_cglist[idxcg_count]; + idxcg_count++; + } + } + // Whats = [w/(q/np.sqrt(np.pi * 4 / (2 * l + 1)))**3 if abs(q) > 1.0e-6 else 0.0 for l,q,w in zip(range(1,max_l+1),Qs,Ws)] + if (d_qnarray(iatom,il) < QEPSILON) + d_qnarray(iatom,jj++) = 0.0; + else { + const double qnormfac = sqrt(MY_4PI/(2*l+1)); + const double qnfac = qnormfac/d_qnarray(iatom,il); + d_qnarray(iatom,jj++) = wlsum/sqrt(2.0*l+1.0)*(qnfac*qnfac*qnfac); + } + } + } + + // Calculate components of Q_l, for l=qlcomp + + if (qlcompflag) { + const int il = iqlcomp; + const int l = qlcomp; + if (d_qnarray(iatom,il) < QEPSILON) + for(int m = 0; m < 2*l+1; m++) { + d_qnarray(iatom,jj++) = 0.0; + d_qnarray(iatom,jj++) = 0.0; + } + else { + const double qnormfac = sqrt(MY_4PI/(2*l+1)); + const double qnfac = qnormfac/d_qnarray(iatom,il); + for(int m = 0; m < 2*l+1; m++) { + d_qnarray(iatom,jj++) = d_qnm(iatom,il,m).re * qnfac; + d_qnarray(iatom,jj++) = d_qnm(iatom,il,m).im * qnfac; + } + } + } + +} + +/* ---------------------------------------------------------------------- + polar prefactor for spherical harmonic Y_l^m, where + Y_l^m (theta, phi) = prefactor(l, m, cos(theta)) * exp(i*m*phi) +------------------------------------------------------------------------- */ + +template +KOKKOS_INLINE_FUNCTION +double ComputeOrientOrderAtomKokkos::polar_prefactor(int l, int m, double costheta) const +{ + const int mabs = abs(m); + + double prefactor = 1.0; + for (int i=l-mabs+1; i < l+mabs+1; ++i) + prefactor *= static_cast(i); + + prefactor = sqrt(static_cast(2*l+1)/(MY_4PI*prefactor)) + * associated_legendre(l,mabs,costheta); + + if ((m < 0) && (m % 2)) prefactor = -prefactor; + + return prefactor; +} + +/* ---------------------------------------------------------------------- + associated legendre polynomial +------------------------------------------------------------------------- */ + +template +KOKKOS_INLINE_FUNCTION +double ComputeOrientOrderAtomKokkos::associated_legendre(int l, int m, double x) const +{ + if (l < m) return 0.0; + + double p(1.0), pm1(0.0), pm2(0.0); + + if (m != 0) { + const double sqx = sqrt(1.0-x*x); + for (int i=1; i < m+1; ++i) + p *= static_cast(2*i-1) * sqx; + } + + for (int i=m+1; i < l+1; ++i) { + pm2 = pm1; + pm1 = p; + p = (static_cast(2*i-1)*x*pm1 + - static_cast(i+m-1)*pm2) / static_cast(i-m); + } + + return p; +} + +/* ---------------------------------------------------------------------- + assign Clebsch-Gordan coefficients + using the quasi-binomial formula VMK 8.2.1(3) + specialized for case j1=j2=j=l +------------------------------------------------------------------------- */ + +template +void ComputeOrientOrderAtomKokkos::init_clebsch_gordan() +{ + double sum,dcg,sfaccg, sfac1, sfac2; + int m, aa2, bb2, cc2; + int ifac, idxcg_count; + + idxcg_count = 0; + for (int il = 0; il < nqlist; il++) { + int l = qlist[il]; + for(int m1 = 0; m1 < 2*l+1; m1++) + for(int m2 = MAX(0,l-m1); m2 < MIN(2*l+1,3*l-m1+1); m2++) + idxcg_count++; + } + idxcg_max = idxcg_count; + d_cglist = t_sna_1d("orientorder/atom:d_cglist",idxcg_max); + auto h_cglist = Kokkos::create_mirror_view(d_cglist); + + idxcg_count = 0; + for (int il = 0; il < nqlist; il++) { + int l = qlist[il]; + for(int m1 = 0; m1 < 2*l+1; m1++) { + aa2 = m1 - l; + for(int m2 = MAX(0,l-m1); m2 < MIN(2*l+1,3*l-m1+1); m2++) { + bb2 = m2 - l; + m = aa2 + bb2 + l; + + sum = 0.0; + for (int z = MAX(0, MAX(-aa2, bb2)); + z <= MIN(l, MIN(l - aa2, l + bb2)); z++) { + ifac = z % 2 ? -1 : 1; + sum += ifac / + (factorial(z) * + factorial(l - z) * + factorial(l - aa2 - z) * + factorial(l + bb2 - z) * + factorial(aa2 + z) * + factorial(-bb2 + z)); + } + + cc2 = m - l; + sfaccg = sqrt(factorial(l + aa2) * + factorial(l - aa2) * + factorial(l + bb2) * + factorial(l - bb2) * + factorial(l + cc2) * + factorial(l - cc2) * + (2*l + 1)); + + sfac1 = factorial(3*l + 1); + sfac2 = factorial(l); + dcg = sqrt(sfac2*sfac2*sfac2 / sfac1); + + h_cglist[idxcg_count] = sum * dcg * sfaccg; + idxcg_count++; + } + } + } + Kokkos::deep_copy(d_cglist,h_cglist); +} + +namespace LAMMPS_NS { +template class ComputeOrientOrderAtomKokkos; +#ifdef KOKKOS_ENABLE_CUDA +template class ComputeOrientOrderAtomKokkos; +#endif +} diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.h b/src/KOKKOS/compute_orientorder_atom_kokkos.h new file mode 100644 index 0000000000..b0e96df0ec --- /dev/null +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.h @@ -0,0 +1,150 @@ +/* -*- 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 COMPUTE_CLASS + +ComputeStyle(orientorder/atom/kk,ComputeOrientOrderAtomKokkos) +ComputeStyle(orientorder/atom/kk/device,ComputeOrientOrderAtomKokkos) +ComputeStyle(orientorder/atom/kk/host,ComputeOrientOrderAtomKokkos) + +#else + +#ifndef LMP_COMPUTE_ORIENTORDER_ATOM_KOKKOS_H +#define LMP_COMPUTE_ORIENTORDER_ATOM_KOKKOS_H + +#include "compute_orientorder_atom.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +typedef double SNAreal; + +struct alignas(2*sizeof(SNAreal)) SNAcomplex{ + SNAreal re, im; + + KOKKOS_INLINE_FUNCTION + SNAcomplex() : re(0),im(0) + {} + + KOKKOS_INLINE_FUNCTION + SNAcomplex(SNAreal real_in, SNAreal imag_in) + :re(real_in),im(imag_in) + {} +}; + +struct TagComputeOrientOrderAtomNeigh{}; +struct TagComputeOrientOrderAtomSelect3{}; +struct TagComputeOrientOrderAtomBOOP1{}; +struct TagComputeOrientOrderAtomBOOP2{}; + +template +class ComputeOrientOrderAtomKokkos : public ComputeOrientOrderAtom { + public: + typedef Kokkos::View t_sna_1i; + typedef Kokkos::View t_sna_1d; + typedef Kokkos::View > t_sna_1d_atomic; + typedef Kokkos::View t_sna_2i_lr; + typedef Kokkos::View > t_sna_2i_lr_um; + typedef Kokkos::View t_sna_2i; + typedef Kokkos::View t_sna_2d; + typedef Kokkos::View t_sna_2d_lr; + typedef Kokkos::DualView tdual_sna_2d_lr; + typedef Kokkos::View > t_sna_2d_lr_um; + typedef Kokkos::View t_sna_3d; + typedef Kokkos::View t_sna_3d_lr; + typedef Kokkos::View > t_sna_3d_lr_um; + typedef Kokkos::View t_sna_4d; + typedef Kokkos::View t_sna_3d3; + typedef Kokkos::View t_sna_5d; + + typedef Kokkos::View t_sna_1c; + typedef Kokkos::View > t_sna_1c_atomic; + typedef Kokkos::View t_sna_2c; + typedef Kokkos::View t_sna_2c_lr; + typedef Kokkos::View t_sna_3c; + typedef Kokkos::View t_sna_4c; + typedef Kokkos::View t_sna_3c3; + typedef Kokkos::View t_sna_5c; + + typedef DeviceType device_type; + typedef ArrayTypes AT; + typedef int value_type; + + ComputeOrientOrderAtomKokkos(class LAMMPS *, int, char **); + ~ComputeOrientOrderAtomKokkos(); + void init(); + void compute_peratom(); + t_sna_1i d_qlist; + + KOKKOS_INLINE_FUNCTION + void operator() (TagComputeOrientOrderAtomNeigh, const typename Kokkos::TeamPolicy::member_type& team) const; + + KOKKOS_INLINE_FUNCTION + void operator() (TagComputeOrientOrderAtomSelect3, const int& ii) const; + + KOKKOS_INLINE_FUNCTION + void operator() (TagComputeOrientOrderAtomBOOP1, const typename Kokkos::TeamPolicy::member_type& team) const; + + KOKKOS_INLINE_FUNCTION + void operator() (TagComputeOrientOrderAtomBOOP2, const int& ii) const; + + private: + int inum; + + typename AT::t_x_array_randomread x; + typename ArrayTypes::t_int_1d mask; + + typename AT::t_neighbors_2d d_neighbors; + typename AT::t_int_1d_randomread d_ilist; + typename AT::t_int_1d_randomread d_numneigh; + + t_sna_1i d_ncount; + t_sna_2d_lr d_distsq; + t_sna_2i_lr d_nearest; + t_sna_3d_lr d_rlist; + + t_sna_2d_lr_um d_distsq_um; + t_sna_2i_lr_um d_nearest_um; + t_sna_3d_lr_um d_rlist_um; + + tdual_sna_2d_lr k_qnarray; + t_sna_2d_lr d_qnarray; + t_sna_3c d_qnm; + + KOKKOS_INLINE_FUNCTION + void select3(int, int, int) const; + + KOKKOS_INLINE_FUNCTION + void calc_boop1(int, int, int) const; + + KOKKOS_INLINE_FUNCTION + void calc_boop2(int, int) const; + + KOKKOS_INLINE_FUNCTION + double polar_prefactor(int, int, double) const; + + KOKKOS_INLINE_FUNCTION + double associated_legendre(int, int, double) const; + + void init_clebsch_gordan(); + t_sna_1d d_cglist; // Clebsch-Gordan coeffs +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +*/ diff --git a/src/KSPACE/pair_born_coul_long.cpp b/src/KSPACE/pair_born_coul_long.cpp index b5b3eda64f..b4d050412a 100644 --- a/src/KSPACE/pair_born_coul_long.cpp +++ b/src/KSPACE/pair_born_coul_long.cpp @@ -47,6 +47,7 @@ PairBornCoulLong::PairBornCoulLong(LAMMPS *lmp) : Pair(lmp) ewaldflag = pppmflag = 1; ftable = NULL; writedata = 1; + cut_respa = NULL; } /* ---------------------------------------------------------------------- */ diff --git a/src/KSPACE/pair_buck_long_coul_long.cpp b/src/KSPACE/pair_buck_long_coul_long.cpp index 7f369045c3..6c731b73b3 100644 --- a/src/KSPACE/pair_buck_long_coul_long.cpp +++ b/src/KSPACE/pair_buck_long_coul_long.cpp @@ -52,6 +52,7 @@ PairBuckLongCoulLong::PairBuckLongCoulLong(LAMMPS *lmp) : Pair(lmp) writedata = 1; ftable = NULL; fdisptable = NULL; + cut_respa = NULL; } /* ---------------------------------------------------------------------- diff --git a/src/KSPACE/pair_coul_long.cpp b/src/KSPACE/pair_coul_long.cpp index 004835007d..9a9f2f3783 100644 --- a/src/KSPACE/pair_coul_long.cpp +++ b/src/KSPACE/pair_coul_long.cpp @@ -46,6 +46,7 @@ PairCoulLong::PairCoulLong(LAMMPS *lmp) : Pair(lmp) ewaldflag = pppmflag = 1; ftable = NULL; qdist = 0.0; + cut_respa = NULL; } /* ---------------------------------------------------------------------- */ diff --git a/src/KSPACE/pair_lj_charmm_coul_long.cpp b/src/KSPACE/pair_lj_charmm_coul_long.cpp index 22ed923b49..390005d80e 100644 --- a/src/KSPACE/pair_lj_charmm_coul_long.cpp +++ b/src/KSPACE/pair_lj_charmm_coul_long.cpp @@ -51,6 +51,7 @@ PairLJCharmmCoulLong::PairLJCharmmCoulLong(LAMMPS *lmp) : Pair(lmp) implicit = 0; mix_flag = ARITHMETIC; writedata = 1; + cut_respa = NULL; } /* ---------------------------------------------------------------------- */ diff --git a/src/KSPACE/pair_lj_charmmfsw_coul_long.cpp b/src/KSPACE/pair_lj_charmmfsw_coul_long.cpp index ce7fda5f18..0371ac42c5 100644 --- a/src/KSPACE/pair_lj_charmmfsw_coul_long.cpp +++ b/src/KSPACE/pair_lj_charmmfsw_coul_long.cpp @@ -55,6 +55,7 @@ PairLJCharmmfswCoulLong::PairLJCharmmfswCoulLong(LAMMPS *lmp) : Pair(lmp) implicit = 0; mix_flag = ARITHMETIC; writedata = 1; + cut_respa = NULL; // short-range/long-range flag accessed by DihedralCharmmfsw diff --git a/src/KSPACE/pair_lj_cut_coul_long.cpp b/src/KSPACE/pair_lj_cut_coul_long.cpp index 23e182435d..ff20dc2570 100644 --- a/src/KSPACE/pair_lj_cut_coul_long.cpp +++ b/src/KSPACE/pair_lj_cut_coul_long.cpp @@ -53,6 +53,7 @@ PairLJCutCoulLong::PairLJCutCoulLong(LAMMPS *lmp) : Pair(lmp) writedata = 1; ftable = NULL; qdist = 0.0; + cut_respa = NULL; } /* ---------------------------------------------------------------------- */ diff --git a/src/KSPACE/pair_lj_long_coul_long.cpp b/src/KSPACE/pair_lj_long_coul_long.cpp index 4af3cdeecd..94955d2d6d 100644 --- a/src/KSPACE/pair_lj_long_coul_long.cpp +++ b/src/KSPACE/pair_lj_long_coul_long.cpp @@ -55,6 +55,7 @@ PairLJLongCoulLong::PairLJLongCoulLong(LAMMPS *lmp) : Pair(lmp) ftable = NULL; fdisptable = NULL; qdist = 0.0; + cut_respa = NULL; } /* ---------------------------------------------------------------------- diff --git a/src/USER-PLUMED/fix_plumed.cpp b/src/USER-PLUMED/fix_plumed.cpp index b02de2af0d..e1f0ea0bfe 100644 --- a/src/USER-PLUMED/fix_plumed.cpp +++ b/src/USER-PLUMED/fix_plumed.cpp @@ -78,8 +78,9 @@ FixPlumed::FixPlumed(LAMMPS *lmp, int narg, char **arg) : int api_version; p->cmd("getApiVersion",&api_version); - if (api_version > 6) - error->all(FLERR,"Incompatible API version for PLUMED in fix plumed"); + if ((api_version < 5) || (api_version > 7)) + error->all(FLERR,"Incompatible API version for PLUMED in fix plumed. " + "Only Plumed 2.4.x, 2.5.x, and 2.6.x are tested and supported."); // If the -partition option is activated then enable // inter-partition communication diff --git a/src/compute_orientorder_atom.cpp b/src/compute_orientorder_atom.cpp index dcb104fc3a..2abe4e3bb3 100644 --- a/src/compute_orientorder_atom.cpp +++ b/src/compute_orientorder_atom.cpp @@ -162,6 +162,8 @@ ComputeOrientOrderAtom::ComputeOrientOrderAtom(LAMMPS *lmp, int narg, char **arg ComputeOrientOrderAtom::~ComputeOrientOrderAtom() { + if (copymode) return; + memory->destroy(qnarray); memory->destroy(distsq); memory->destroy(rlist); diff --git a/src/compute_orientorder_atom.h b/src/compute_orientorder_atom.h index 643875ccd0..46894db373 100644 --- a/src/compute_orientorder_atom.h +++ b/src/compute_orientorder_atom.h @@ -28,16 +28,16 @@ class ComputeOrientOrderAtom : public Compute { public: ComputeOrientOrderAtom(class LAMMPS *, int, char **); ~ComputeOrientOrderAtom(); - void init(); + virtual void init(); void init_list(int, class NeighList *); - void compute_peratom(); + virtual void compute_peratom(); double memory_usage(); double cutsq; int iqlcomp, qlcomp, qlcompflag, wlflag, wlhatflag; int *qlist; int nqlist; - private: + protected: int nmax,maxneigh,ncol,nnn; class NeighList *list; double *distsq; @@ -59,7 +59,7 @@ class ComputeOrientOrderAtom : public Compute { static const int nmaxfactorial = 167; static const double nfac_table[]; double factorial(int); - void init_clebsch_gordan(); + virtual void init_clebsch_gordan(); double *cglist; // Clebsch-Gordan coeffs int idxcg_max; }; diff --git a/src/lmptype.h b/src/lmptype.h index c1902e7ebe..65e46535fc 100644 --- a/src/lmptype.h +++ b/src/lmptype.h @@ -28,13 +28,6 @@ #ifndef LMP_LMPTYPE_H #define LMP_LMPTYPE_H -// C++11 check -#ifndef LAMMPS_CXX98 -#if __cplusplus <= 199711L - #error LAMMPS is planning to transition to C++11. To disable this error please use a C++11 compliant compiler, enable C++11 (or later) compliance, or define LAMMPS_CXX98 in your makefile -#endif -#endif - #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS #endif diff --git a/src/modify.cpp b/src/modify.cpp index 101540f786..864bc8f2b4 100644 --- a/src/modify.cpp +++ b/src/modify.cpp @@ -50,6 +50,7 @@ Modify::Modify(LAMMPS *lmp) : Pointers(lmp) n_pre_force_respa = n_post_force_respa = n_final_integrate_respa = 0; n_min_pre_exchange = n_min_pre_force = n_min_pre_reverse = 0; n_min_post_force = n_min_energy = 0; + n_timeflag = -1; fix = NULL; fmask = NULL; @@ -526,6 +527,11 @@ void Modify::thermo_energy_atom(int nlocal, double *energy) void Modify::post_run() { for (int i = 0; i < nfix; i++) fix[i]->post_run(); + + // must reset this to its default value, since computes may be added + // or removed between runs and with this change we will redirect any + // calls to addstep_compute() to addstep_compute_all() instead. + n_timeflag = -1; } /* ---------------------------------------------------------------------- @@ -1283,6 +1289,14 @@ void Modify::clearstep_compute() void Modify::addstep_compute(bigint newstep) { + // If we are called before the first run init, n_timeflag is not yet + // initialized, thus defer to addstep_compute_all() instead + + if (n_timeflag < 0) { + addstep_compute_all(newstep); + return; + } + for (int icompute = 0; icompute < n_timeflag; icompute++) if (compute[list_timeflag[icompute]]->invoked_flag) compute[list_timeflag[icompute]]->addstep(newstep); diff --git a/src/pair_coul_streitz.h b/src/pair_coul_streitz.h index c304365270..0f23c111c7 100644 --- a/src/pair_coul_streitz.h +++ b/src/pair_coul_streitz.h @@ -55,7 +55,6 @@ class PairCoulStreitz : public Pair { // Kspace parameters int kspacetype; double cut_coul, cut_coulsq; - double *cut_respa; double **scale; // Wolf diff --git a/src/pair_lj96_cut.cpp b/src/pair_lj96_cut.cpp index f554872965..8be6fefa44 100644 --- a/src/pair_lj96_cut.cpp +++ b/src/pair_lj96_cut.cpp @@ -41,6 +41,7 @@ PairLJ96Cut::PairLJ96Cut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; writedata = 1; + cut_respa = NULL; } /* ---------------------------------------------------------------------- */ diff --git a/src/pair_mie_cut.cpp b/src/pair_mie_cut.cpp index 4ce82381f3..f031401a00 100644 --- a/src/pair_mie_cut.cpp +++ b/src/pair_mie_cut.cpp @@ -40,6 +40,7 @@ using namespace MathConst; PairMIECut::PairMIECut(LAMMPS *lmp) : Pair(lmp) { respa_enable = 1; + cut_respa = NULL; } /* ---------------------------------------------------------------------- */ diff --git a/src/reader_native.cpp b/src/reader_native.cpp index da2c97bbe5..26cb45a686 100644 --- a/src/reader_native.cpp +++ b/src/reader_native.cpp @@ -17,6 +17,7 @@ #include "atom.h" #include "memory.h" #include "error.h" +#include "utils.h" using namespace LAMMPS_NS; @@ -56,12 +57,15 @@ int ReaderNative::read_time(bigint &ntimestep) char *eof = fgets(line,MAXLINE,fp); if (eof == NULL) return 1; - // skip over unit information, if present. + // skip over unit and time information, if present. - if (strstr(line,"ITEM: UNITS") == line) + if (utils::strmatch(line,"^\\s*ITEM: UNITS\\s*$")) read_lines(2); - if (strstr(line,"ITEM: TIMESTEP") != line) + if (utils::strmatch(line,"^\\s*ITEM: TIME\\s*$")) + read_lines(2); + + if (!utils::strmatch(line,"^\\s*ITEM: TIMESTEP\\s*$")) error->one(FLERR,"Dump file is incorrectly formatted"); read_lines(1); diff --git a/src/set.cpp b/src/set.cpp index 9807b07ea4..e3b1962d5d 100644 --- a/src/set.cpp +++ b/src/set.cpp @@ -1084,13 +1084,18 @@ void Set::setrandom(int keyword) ranmars->select_subset(nsubset,count,flag,work); // change types of selected atoms + // flag vector from select_subset() is only for eligible atoms count = 0; - for (i = 0; i < nlocal; i++) - if (select[i] && flag[i]) { + int eligible = 0; + for (i = 0; i < nlocal; i++) { + if (!select[i]) continue; + if (flag[eligible]) { atom->type[i] = newtype; count++; } + eligible++; + } // clean up diff --git a/src/suffix.h b/src/suffix.h index 88629aa796..177990eb68 100644 --- a/src/suffix.h +++ b/src/suffix.h @@ -16,15 +16,16 @@ namespace LAMMPS_NS { -enum Suffix { - NONE = 0, - OPT = 1<<0, - GPU = 1<<1, - OMP = 1<<2, - INTEL = 1<<3, - KOKKOS = 1<<4 -}; - +namespace Suffix { + enum { + NONE = 0, + OPT = 1<<0, + GPU = 1<<1, + OMP = 1<<2, + INTEL = 1<<3, + KOKKOS = 1<<4 + }; +} } #endif diff --git a/src/version.h b/src/version.h index e43844a567..352680380b 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define LAMMPS_VERSION "4 Feb 2020" +#define LAMMPS_VERSION "18 Feb 2020" -- GitLab From 796e1ac4e90d94bfdefb962af4b48c6eb659908e Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 24 Feb 2020 13:29:22 -0700 Subject: [PATCH 033/577] Update docs --- doc/src/compute_orientorder_atom.rst | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/doc/src/compute_orientorder_atom.rst b/doc/src/compute_orientorder_atom.rst index b864db82a7..7a294bed5e 100644 --- a/doc/src/compute_orientorder_atom.rst +++ b/doc/src/compute_orientorder_atom.rst @@ -3,6 +3,9 @@ compute orientorder/atom command ================================ +compute orientorder/atom/kk command +======================= + Syntax """""" @@ -132,6 +135,30 @@ too frequently. :doc:`special_bonds ` command that includes all pairs in the neighbor list. +---------- + + +Styles with a *gpu*\ , *intel*\ , *kk*\ , *omp*\ , or *opt* suffix are +functionally the same as the corresponding style without the suffix. +They have been optimized to run faster, depending on your available +hardware, as discussed on the :doc:`Speed packages ` doc +page. The accelerated styles take the same arguments and should +produce the same results, except for round-off and precision issues. + +These accelerated styles are part of the GPU, USER-INTEL, KOKKOS, +USER-OMP and OPT packages, respectively. They are only enabled if +LAMMPS was built with those packages. See the :doc:`Build package ` doc page for more info. + +You can specify the accelerated styles explicitly in your input script +by including their suffix, or you can use the :doc:`-suffix command-line switch ` when you invoke LAMMPS, or you can use the +:doc:`suffix ` command in your input script. + +See the :doc:`Speed packages ` doc page for more +instructions on how to use the accelerated styles effectively. + + +---------- + **Output info:** This compute calculates a per-atom array with *nlvalues* columns, -- GitLab From 29075c8257b20a6bb6df2b9bd9e8f89f672ce9b9 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 24 Feb 2020 13:31:13 -0700 Subject: [PATCH 034/577] Fix compile issue --- src/KOKKOS/compute_orientorder_atom_kokkos.h | 15 ------------ src/KOKKOS/kokkos_type.h | 18 +++++++++++++++ src/KOKKOS/sna_kokkos.h | 24 -------------------- 3 files changed, 18 insertions(+), 39 deletions(-) diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.h b/src/KOKKOS/compute_orientorder_atom_kokkos.h index b0e96df0ec..9caa17136b 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.h +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.h @@ -27,21 +27,6 @@ ComputeStyle(orientorder/atom/kk/host,ComputeOrientOrderAtomKokkos) namespace LAMMPS_NS { -typedef double SNAreal; - -struct alignas(2*sizeof(SNAreal)) SNAcomplex{ - SNAreal re, im; - - KOKKOS_INLINE_FUNCTION - SNAcomplex() : re(0),im(0) - {} - - KOKKOS_INLINE_FUNCTION - SNAcomplex(SNAreal real_in, SNAreal imag_in) - :re(real_in),im(imag_in) - {} -}; - struct TagComputeOrientOrderAtomNeigh{}; struct TagComputeOrientOrderAtomSelect3{}; struct TagComputeOrientOrderAtomBOOP1{}; diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index d21b9eecd2..7b6e86106d 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -1023,6 +1023,24 @@ struct params_lj_coul { F_FLOAT cut_ljsq,cut_coulsq,lj1,lj2,lj3,lj4,offset; }; +// Pair SNAP + +typedef double SNAreal; + +//typedef struct { SNAreal re, im; } SNAcomplex; +struct alignas(2*sizeof(SNAreal)) SNAcomplex{ + SNAreal re, im; + + KOKKOS_INLINE_FUNCTION + SNAcomplex() : re(0),im(0) + {} + + KOKKOS_INLINE_FUNCTION + SNAcomplex(SNAreal real_in, SNAreal imag_in) + :re(real_in),im(imag_in) + {} +}; + #if defined(KOKKOS_ENABLE_CXX11) #undef ISFINITE #define ISFINITE(x) std::isfinite(x) diff --git a/src/KOKKOS/sna_kokkos.h b/src/KOKKOS/sna_kokkos.h index 775c8eead4..12c986cc93 100644 --- a/src/KOKKOS/sna_kokkos.h +++ b/src/KOKKOS/sna_kokkos.h @@ -25,30 +25,6 @@ namespace LAMMPS_NS { -typedef double SNAreal; - -//typedef struct { SNAreal re, im; } SNAcomplex; -struct alignas(2*sizeof(SNAreal)) SNAcomplex{ - SNAreal re, im; - - KOKKOS_INLINE_FUNCTION - SNAcomplex() : re(0),im(0) - {} - - KOKKOS_INLINE_FUNCTION - SNAcomplex(SNAreal real_in, SNAreal imag_in) - :re(real_in),im(imag_in) - {} -}; - -//struct SNAKK_ZINDICES { -// int j1, j2, j, ma1min, ma2max, mb1min, mb2max, na, nb, jju; -//}; -// -//struct SNAKK_BINDICES { -// int j1, j2, j; -//}; - template class SNAKokkos { -- GitLab From c505058c5c7b9235e0d7e8e580d686974ddc0a96 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Mon, 24 Feb 2020 15:43:29 -0700 Subject: [PATCH 035/577] Add flag for Kokkos computes --- src/KOKKOS/compute_orientorder_atom_kokkos.cpp | 1 + src/KOKKOS/compute_temp_kokkos.cpp | 1 + src/compute.cpp | 1 + src/compute.h | 2 +- 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp index 7915e4faa9..65bb08b18d 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp @@ -52,6 +52,7 @@ template ComputeOrientOrderAtomKokkos::ComputeOrientOrderAtomKokkos(LAMMPS *lmp, int narg, char **arg) : ComputeOrientOrderAtom(lmp, narg, arg) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; execution_space = ExecutionSpaceFromDevice::space; datamask_read = EMPTY_MASK; diff --git a/src/KOKKOS/compute_temp_kokkos.cpp b/src/KOKKOS/compute_temp_kokkos.cpp index a2fcf63125..f5547d0200 100644 --- a/src/KOKKOS/compute_temp_kokkos.cpp +++ b/src/KOKKOS/compute_temp_kokkos.cpp @@ -31,6 +31,7 @@ template ComputeTempKokkos::ComputeTempKokkos(LAMMPS *lmp, int narg, char **arg) : ComputeTemp(lmp, narg, arg) { + kokkosable = 1; atomKK = (AtomKokkos *) atom; execution_space = ExecutionSpaceFromDevice::space; diff --git a/src/compute.cpp b/src/compute.cpp index cc92d2b5d3..4009396eb0 100644 --- a/src/compute.cpp +++ b/src/compute.cpp @@ -102,6 +102,7 @@ Compute::Compute(LAMMPS *lmp, int narg, char **arg) : datamask_modify = ALL_MASK; copymode = 0; + kokkosable = 0; } /* ---------------------------------------------------------------------- */ diff --git a/src/compute.h b/src/compute.h index c28af32c26..66974bf106 100644 --- a/src/compute.h +++ b/src/compute.h @@ -91,7 +91,7 @@ class Compute : protected Pointers { ExecutionSpace execution_space; unsigned int datamask_read,datamask_modify; - int copymode; + int copymode,kokkosable; Compute(class LAMMPS *, int, char **); virtual ~Compute(); -- GitLab From 59370d797f46ae2bfb66cc3ace93173f646bdc20 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Tue, 25 Feb 2020 08:58:01 -0700 Subject: [PATCH 036/577] Use more generic type for k_qnarray --- src/KOKKOS/compute_orientorder_atom_kokkos.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.h b/src/KOKKOS/compute_orientorder_atom_kokkos.h index 9caa17136b..d99942533f 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.h +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.h @@ -102,8 +102,8 @@ class ComputeOrientOrderAtomKokkos : public ComputeOrientOrderAtom { t_sna_2i_lr_um d_nearest_um; t_sna_3d_lr_um d_rlist_um; - tdual_sna_2d_lr k_qnarray; - t_sna_2d_lr d_qnarray; + DAT::tdual_float_2d k_qnarray; + typename AT::t_float_2d d_qnarray; t_sna_3c d_qnm; KOKKOS_INLINE_FUNCTION -- GitLab From a3c5c49a6b8316fa4a4a9fcf2ca1513d2f42f6be Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Tue, 25 Feb 2020 10:20:21 -0700 Subject: [PATCH 037/577] Make k_qnarray public --- src/KOKKOS/compute_orientorder_atom_kokkos.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.h b/src/KOKKOS/compute_orientorder_atom_kokkos.h index d99942533f..01d9993af2 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.h +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.h @@ -83,6 +83,9 @@ class ComputeOrientOrderAtomKokkos : public ComputeOrientOrderAtom { KOKKOS_INLINE_FUNCTION void operator() (TagComputeOrientOrderAtomBOOP2, const int& ii) const; + DAT::tdual_float_2d k_qnarray; + typename AT::t_float_2d d_qnarray; + private: int inum; @@ -102,8 +105,6 @@ class ComputeOrientOrderAtomKokkos : public ComputeOrientOrderAtom { t_sna_2i_lr_um d_nearest_um; t_sna_3d_lr_um d_rlist_um; - DAT::tdual_float_2d k_qnarray; - typename AT::t_float_2d d_qnarray; t_sna_3c d_qnm; KOKKOS_INLINE_FUNCTION -- GitLab From a44e49e27630eb92873b0a93cd95ea600883fa1d Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Tue, 25 Feb 2020 10:22:30 -0700 Subject: [PATCH 038/577] Add Kokkos version of compute coord/atom --- src/KOKKOS/Install.sh | 2 + src/KOKKOS/compute_coord_atom_kokkos.cpp | 249 +++++++++++++++++++++++ src/KOKKOS/compute_coord_atom_kokkos.h | 78 +++++++ src/compute_coord_atom.cpp | 2 + src/compute_coord_atom.h | 8 +- 5 files changed, 335 insertions(+), 4 deletions(-) create mode 100644 src/KOKKOS/compute_coord_atom_kokkos.cpp create mode 100644 src/KOKKOS/compute_coord_atom_kokkos.h diff --git a/src/KOKKOS/Install.sh b/src/KOKKOS/Install.sh index 540389f599..e9a8ff96c8 100755 --- a/src/KOKKOS/Install.sh +++ b/src/KOKKOS/Install.sh @@ -85,6 +85,8 @@ action comm_kokkos.cpp action comm_kokkos.h action comm_tiled_kokkos.cpp action comm_tiled_kokkos.h +action compute_coord_atom_kokkos.cpp +action compute_coord_atom_kokkos.h action compute_orientorder_atom_kokkos.cpp action compute_orientorder_atom_kokkos.h action compute_temp_kokkos.cpp diff --git a/src/KOKKOS/compute_coord_atom_kokkos.cpp b/src/KOKKOS/compute_coord_atom_kokkos.cpp new file mode 100644 index 0000000000..3ce4e3b852 --- /dev/null +++ b/src/KOKKOS/compute_coord_atom_kokkos.cpp @@ -0,0 +1,249 @@ +/* ---------------------------------------------------------------------- + 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_coord_atom_kokkos.h" +#include +#include +#include "compute_orientorder_atom_kokkos.h" +#include "atom_kokkos.h" +#include "update.h" +#include "modify.h" +#include "neighbor_kokkos.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "force.h" +#include "pair.h" +#include "comm.h" +#include "group.h" +#include "memory_kokkos.h" +#include "error.h" +#include "atom_masks.h" + +using namespace LAMMPS_NS; + +#define INVOKED_PERATOM 8 + +/* ---------------------------------------------------------------------- */ + +template +ComputeCoordAtomKokkos::ComputeCoordAtomKokkos(LAMMPS *lmp, int narg, char **arg) : + ComputeCoordAtom(lmp, narg, arg) +{ + kokkosable = 1; + atomKK = (AtomKokkos *) atom; + execution_space = ExecutionSpaceFromDevice::space; + datamask_read = EMPTY_MASK; + datamask_modify = EMPTY_MASK; + + d_typelo = typename AT::t_int_1d("coord/atom:typelo",ncol); + d_typehi = typename AT::t_int_1d("coord/atom:typehi",ncol); + + auto h_typelo = Kokkos::create_mirror_view(d_typelo); + auto h_typehi = Kokkos::create_mirror_view(d_typehi); + + for (int i = 0; i < ncol; i++) { + h_typelo(i) = typelo[i]; + h_typehi(i) = typehi[i]; + } + + Kokkos::deep_copy(d_typelo,h_typelo); + Kokkos::deep_copy(d_typehi,h_typehi); +} + +/* ---------------------------------------------------------------------- */ + +template +ComputeCoordAtomKokkos::~ComputeCoordAtomKokkos() +{ + if (copymode) return; + + memoryKK->destroy_kokkos(k_cvec,cvec); + memoryKK->destroy_kokkos(k_carray,carray); +} + +/* ---------------------------------------------------------------------- */ + +template +void ComputeCoordAtomKokkos::init() +{ + ComputeCoordAtom::init(); + + // need an occasional full neighbor list + + // irequest = neigh request made by parent class + + int irequest = neighbor->nrequest - 1; + + neighbor->requests[irequest]-> + kokkos_host = Kokkos::Impl::is_same::value && + !Kokkos::Impl::is_same::value; + neighbor->requests[irequest]-> + kokkos_device = Kokkos::Impl::is_same::value; +} + +/* ---------------------------------------------------------------------- */ + +template +void ComputeCoordAtomKokkos::compute_peratom() +{ + invoked_peratom = update->ntimestep; + + // grow coordination array if necessary + + if (atom->nmax > nmax) { + if (ncol == 1) { + memoryKK->destroy_kokkos(k_cvec,cvec); + nmax = atom->nmax; + memoryKK->create_kokkos(k_cvec,cvec,nmax,"coord/atom:cvec"); + vector_atom = cvec; + d_cvec = k_cvec.template view(); + } else { + memoryKK->destroy_kokkos(k_carray,carray); + nmax = atom->nmax; + memoryKK->create_kokkos(k_carray,carray,nmax,ncol,"coord/atom:carray"); + array_atom = carray; + d_carray = k_carray.template view(); + } + } + + if (cstyle == ORIENT) { + if (!(c_orientorder->invoked_flag & INVOKED_PERATOM)) { + c_orientorder->compute_peratom(); + c_orientorder->invoked_flag |= INVOKED_PERATOM; + } + nqlist = c_orientorder->nqlist; + normv = c_orientorder->array_atom; + comm->forward_comm_compute(this); + + if (!c_orientorder->kokkosable) + error->all(FLERR,"Must use compute orientorder/atom/kk with compute coord/atom/kk"); + + if (c_orientorder->execution_space == Host) { + ComputeOrientOrderAtomKokkos* c_orientorder_kk; + c_orientorder_kk = (ComputeOrientOrderAtomKokkos*) c_orientorder; + c_orientorder_kk->k_qnarray.modify(); + c_orientorder_kk->k_qnarray.sync(); + d_normv = c_orientorder_kk->k_qnarray.view(); + } else { + ComputeOrientOrderAtomKokkos* c_orientorder_kk; + c_orientorder_kk = (ComputeOrientOrderAtomKokkos*) c_orientorder; + c_orientorder_kk->k_qnarray.modify(); + c_orientorder_kk->k_qnarray.sync(); + d_normv = c_orientorder_kk->k_qnarray.view(); + } + } + + // invoke full neighbor list (will copy or build if necessary) + + neighbor->build_one(list); + + inum = list->inum; + NeighListKokkos* k_list = static_cast*>(list); + d_numneigh = k_list->d_numneigh; + d_neighbors = k_list->d_neighbors; + d_ilist = k_list->d_ilist; + + // compute coordination number(s) for each atom in group + // use full neighbor list to count atoms less than cutoff + + atomKK->sync(execution_space,X_MASK|TYPE_MASK|MASK_MASK); + x = atomKK->k_x.view(); + type = atomKK->k_type.view(); + mask = atomKK->k_mask.view(); + + copymode = 1; + if (cstyle == CUTOFF) { + if (ncol == 1) { + typename Kokkos::RangePolicy > policy(0,inum); + Kokkos::parallel_for("ComputeCoordAtom",policy,*this); + } else { + typename Kokkos::RangePolicy > policy(0,inum); + Kokkos::parallel_for("ComputeCoordAtom",policy,*this); + } + } else if (cstyle == ORIENT) { + typename Kokkos::RangePolicy > policy(0,inum); + Kokkos::parallel_for("ComputeCoordAtom",policy,*this); + } + copymode = 0; + + if (ncol == 1 || cstyle == ORIENT) { + k_cvec.modify(); + k_cvec.sync(); + } else { + k_carray.modify(); + k_carray.sync(); + } + +} + +template +template +KOKKOS_INLINE_FUNCTION +void ComputeCoordAtomKokkos::operator()(TagComputeCoordAtom, const int &ii) const +{ + const int i = d_ilist[ii]; + if (NCOL == 1 || CSTYLE == ORIENT) + d_cvec(i) = 0.0; + else + for (int m = 0; m < ncol; m++) d_carray(i,m) = 0.0; + if (mask[i] & groupbit) { + const X_FLOAT xtmp = x(i,0); + const X_FLOAT ytmp = x(i,1); + const X_FLOAT ztmp = x(i,2); + const int jnum = d_numneigh[i]; + + int n = 0; + for (int jj = 0; jj < jnum; jj++) { + int j = d_neighbors(i,jj); + j &= NEIGHMASK; + + if (NCOL == 1) + if (!(mask[j] & jgroupbit)) continue; + + const int jtype = type[j]; + const F_FLOAT delx = x(j,0) - xtmp; + const F_FLOAT dely = x(j,1) - ytmp; + const F_FLOAT delz = x(j,2) - ztmp; + const F_FLOAT rsq = delx*delx + dely*dely + delz*delz; + if (rsq < cutsq) { + if (CSTYLE == CUTOFF) { + if (NCOL == 1) { + if (jtype >= d_typelo[0] && jtype <= d_typehi[0]) + n++; + } else { + for (int m = 0; m < ncol; m++) + if (jtype >= d_typelo[m] && jtype <= d_typehi[m]) + d_carray(i,m) += 1.0; + } + } else if (CSTYLE == ORIENT) { + double dot_product = 0.0; + for (int m=0; m < 2*(2*l+1); m++) { + dot_product += d_normv(i,nqlist+m)*d_normv(j,nqlist+m); + } + if (dot_product > threshold) n++; + } + } + } + + if (NCOL == 1 || CSTYLE == ORIENT) + d_cvec[i] = n; + } + +} + +namespace LAMMPS_NS { +template class ComputeCoordAtomKokkos; +#ifdef KOKKOS_ENABLE_CUDA +template class ComputeCoordAtomKokkos; +#endif +} diff --git a/src/KOKKOS/compute_coord_atom_kokkos.h b/src/KOKKOS/compute_coord_atom_kokkos.h new file mode 100644 index 0000000000..c77e8f8b45 --- /dev/null +++ b/src/KOKKOS/compute_coord_atom_kokkos.h @@ -0,0 +1,78 @@ +/* -*- 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 COMPUTE_CLASS + +ComputeStyle(orientorder/atom/kk,ComputeCoordAtomKokkos) +ComputeStyle(orientorder/atom/kk/device,ComputeCoordAtomKokkos) +ComputeStyle(orientorder/atom/kk/host,ComputeCoordAtomKokkos) + +#else + +#ifndef LMP_COMPUTE_COORD_ATOM_KOKKOS_H +#define LMP_COMPUTE_COORD_ATOM_KOKKOS_H + +#include "compute_coord_atom.h" +#include "kokkos_type.h" + +namespace LAMMPS_NS { + +template +struct TagComputeCoordAtom{}; + +template +class ComputeCoordAtomKokkos : public ComputeCoordAtom { + public: + typedef DeviceType device_type; + typedef ArrayTypes AT; + + ComputeCoordAtomKokkos(class LAMMPS *, int, char **); + virtual ~ComputeCoordAtomKokkos(); + void init(); + void compute_peratom(); + enum {NONE,CUTOFF,ORIENT}; + + template + KOKKOS_INLINE_FUNCTION + void operator()(TagComputeCoordAtom, const int&) const; + + private: + int inum; + + typename AT::t_x_array_randomread x; + typename ArrayTypes::t_int_1d_randomread type; + typename ArrayTypes::t_int_1d mask; + + typename AT::t_neighbors_2d d_neighbors; + typename AT::t_int_1d_randomread d_ilist; + typename AT::t_int_1d_randomread d_numneigh; + + typename AT::t_int_1d d_typelo; + typename AT::t_int_1d d_typehi; + + DAT::tdual_float_1d k_cvec; + typename AT::t_float_1d d_cvec; + DAT::tdual_float_2d k_carray; + typename AT::t_float_2d d_carray; + + typename AT::t_float_2d d_normv; +}; + +} + +#endif +#endif + +/* ERROR/WARNING messages: + +*/ diff --git a/src/compute_coord_atom.cpp b/src/compute_coord_atom.cpp index 30747c1314..8f5e028390 100644 --- a/src/compute_coord_atom.cpp +++ b/src/compute_coord_atom.cpp @@ -119,6 +119,8 @@ ComputeCoordAtom::ComputeCoordAtom(LAMMPS *lmp, int narg, char **arg) : ComputeCoordAtom::~ComputeCoordAtom() { + if (copymode) return; + delete [] group2; delete [] typelo; delete [] typehi; diff --git a/src/compute_coord_atom.h b/src/compute_coord_atom.h index 2a54613cc6..31bab18d87 100644 --- a/src/compute_coord_atom.h +++ b/src/compute_coord_atom.h @@ -27,16 +27,16 @@ namespace LAMMPS_NS { class ComputeCoordAtom : public Compute { public: ComputeCoordAtom(class LAMMPS *, int, char **); - ~ComputeCoordAtom(); - void init(); + virtual ~ComputeCoordAtom(); + virtual void init(); void init_list(int, class NeighList *); - void compute_peratom(); + virtual void compute_peratom(); int pack_forward_comm(int, int *, double *, int, int *); void unpack_forward_comm(int, int, double *); double memory_usage(); enum {NONE,CUTOFF,ORIENT}; - private: + protected: int nmax,ncol; double cutsq; class NeighList *list; -- GitLab From 928ac7f2711021568691a981d115083e14973f0c Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Tue, 25 Feb 2020 10:34:29 -0700 Subject: [PATCH 039/577] Fix typo --- src/KOKKOS/compute_coord_atom_kokkos.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/compute_coord_atom_kokkos.h b/src/KOKKOS/compute_coord_atom_kokkos.h index c77e8f8b45..f292994a18 100644 --- a/src/KOKKOS/compute_coord_atom_kokkos.h +++ b/src/KOKKOS/compute_coord_atom_kokkos.h @@ -13,9 +13,9 @@ #ifdef COMPUTE_CLASS -ComputeStyle(orientorder/atom/kk,ComputeCoordAtomKokkos) -ComputeStyle(orientorder/atom/kk/device,ComputeCoordAtomKokkos) -ComputeStyle(orientorder/atom/kk/host,ComputeCoordAtomKokkos) +ComputeStyle(coord/atom/kk,ComputeCoordAtomKokkos) +ComputeStyle(coord/atom/kk/device,ComputeCoordAtomKokkos) +ComputeStyle(coord/atom/kk/host,ComputeCoordAtomKokkos) #else -- GitLab From eb80fd303192df6fd7e5904131004d6bd7772831 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 26 Feb 2020 14:26:46 -0700 Subject: [PATCH 040/577] Add method to copy Kokkos neighbor list to CPU list --- src/KOKKOS/neigh_list_kokkos.cpp | 24 ++++----- src/KOKKOS/neigh_list_kokkos.h | 16 +++--- src/KOKKOS/npair_copy_kokkos.cpp | 76 ++++++++++++++++++++++++++++ src/KOKKOS/npair_copy_kokkos.h | 3 ++ src/KOKKOS/npair_halffull_kokkos.cpp | 6 ++- src/KOKKOS/npair_kokkos.cpp | 5 +- src/KOKKOS/npair_ssa_kokkos.cpp | 2 + src/neigh_list.cpp | 6 ++- src/neigh_list.h | 1 + src/neighbor.cpp | 27 ++++++---- 10 files changed, 133 insertions(+), 33 deletions(-) diff --git a/src/KOKKOS/neigh_list_kokkos.cpp b/src/KOKKOS/neigh_list_kokkos.cpp index 2b9c5ef645..afaf0dd1b8 100644 --- a/src/KOKKOS/neigh_list_kokkos.cpp +++ b/src/KOKKOS/neigh_list_kokkos.cpp @@ -19,20 +19,20 @@ using namespace LAMMPS_NS; /* ---------------------------------------------------------------------- */ -template -NeighListKokkos::NeighListKokkos(class LAMMPS *lmp):NeighList(lmp) +template +NeighListKokkos::NeighListKokkos(class LAMMPS *lmp):NeighList(lmp) { _stride = 1; maxneighs = 16; kokkos = 1; maxatoms = 0; - execution_space = ExecutionSpaceFromDevice::space; + execution_space = ExecutionSpaceFromDevice::space; }; /* ---------------------------------------------------------------------- */ -template -void NeighListKokkos::grow(int nmax) +template +void NeighListKokkos::grow(int nmax) { // skip if this list is already long enough to store nmax atoms // and maxneighs neighbors @@ -40,14 +40,12 @@ void NeighListKokkos::grow(int nmax) if (nmax <= maxatoms && d_neighbors.extent(1) >= maxneighs) return; maxatoms = nmax; - k_ilist = - DAT::tdual_int_1d("neighlist:ilist",maxatoms); - d_ilist = k_ilist.view(); - d_numneigh = - typename ArrayTypes::t_int_1d("neighlist:numneigh",maxatoms); - d_neighbors = - typename ArrayTypes::t_neighbors_2d("neighlist:neighbors", - maxatoms,maxneighs); + k_ilist = DAT::tdual_int_1d("neighlist:ilist",maxatoms); + d_ilist = k_ilist.view(); + k_numneigh = DAT::tdual_int_1d("neighlist:numneigh",maxatoms); + d_numneigh = k_numneigh.view(); + k_neighbors = DAT::tdual_neighbors_2d("neighlist:neighbors",maxatoms,maxneighs); + d_neighbors = k_neighbors.view(); } /* ---------------------------------------------------------------------- */ diff --git a/src/KOKKOS/neigh_list_kokkos.h b/src/KOKKOS/neigh_list_kokkos.h index 585422c54f..f8195a01f4 100644 --- a/src/KOKKOS/neigh_list_kokkos.h +++ b/src/KOKKOS/neigh_list_kokkos.h @@ -59,7 +59,7 @@ class AtomNeighborsConst const int _stride; }; -template +template class NeighListKokkos: public NeighList { int _stride; @@ -67,10 +67,12 @@ public: int maxneighs; void grow(int nmax); - typename ArrayTypes::t_neighbors_2d d_neighbors; - typename DAT::tdual_int_1d k_ilist; // local indices of I atoms - typename ArrayTypes::t_int_1d d_ilist; - typename ArrayTypes::t_int_1d d_numneigh; // # of J neighs for each I + DAT::tdual_neighbors_2d k_neighbors; + typename ArrayTypes::t_neighbors_2d d_neighbors; + DAT::tdual_int_1d k_ilist; // local indices of I atoms + typename ArrayTypes::t_int_1d d_ilist; + DAT::tdual_int_1d k_numneigh; // # of J neighs for each I + typename ArrayTypes::t_int_1d d_numneigh; NeighListKokkos(class LAMMPS *lmp); @@ -82,8 +84,8 @@ public: KOKKOS_INLINE_FUNCTION static AtomNeighborsConst static_neighbors_const(int i, - typename ArrayTypes::t_neighbors_2d_const const& d_neighbors, - typename ArrayTypes::t_int_1d_const const& d_numneigh) { + typename ArrayTypes::t_neighbors_2d_const const& d_neighbors, + typename ArrayTypes::t_int_1d_const const& d_numneigh) { return AtomNeighborsConst(&d_neighbors(i,0),d_numneigh(i), &d_neighbors(i,1)-&d_neighbors(i,0)); } diff --git a/src/KOKKOS/npair_copy_kokkos.cpp b/src/KOKKOS/npair_copy_kokkos.cpp index 0ce0f4d3ff..b0554db9ea 100644 --- a/src/KOKKOS/npair_copy_kokkos.cpp +++ b/src/KOKKOS/npair_copy_kokkos.cpp @@ -13,6 +13,8 @@ #include "npair_copy_kokkos.h" #include "neigh_list_kokkos.h" +#include "my_page.h" +#include "error.h" using namespace LAMMPS_NS; @@ -30,6 +32,24 @@ void NPairCopyKokkos::build(NeighList *list) { NeighList *listcopy = list->listcopy; + if (list->kokkos) { + if (!listcopy->kokkos) + error->all(FLERR,"Cannot copy non-Kokkos neighbor list to Kokkos neigh list"); + copy_to_kokkos(list); + } else { + if (!listcopy->kokkos) + error->all(FLERR,"Missing Kokkos neighbor list for copy"); + copy_to_cpu(list); + } +} + +/* ---------------------------------------------------------------------- */ + +template +void NPairCopyKokkos::copy_to_kokkos(NeighList *list) +{ + NeighList *listcopy = list->listcopy; + list->inum = listcopy->inum; list->gnum = listcopy->gnum; list->ilist = listcopy->ilist; @@ -44,6 +64,62 @@ void NPairCopyKokkos::build(NeighList *list) list_kk->d_neighbors = listcopy_kk->d_neighbors; } +/* ---------------------------------------------------------------------- */ + +template +void NPairCopyKokkos::copy_to_cpu(NeighList *list) +{ + NeighList *listcopy = list->listcopy; + NeighListKokkos* listcopy_kk = (NeighListKokkos*) listcopy; + + listcopy_kk->k_ilist.template sync(); + listcopy_kk->k_numneigh.template sync(); + listcopy_kk->k_neighbors.template sync(); + + int inum = listcopy->inum; + int gnum = listcopy->gnum; + int inum_all = inum; + if (list->ghost) inum_all += gnum; + auto h_ilist = listcopy_kk->k_ilist.h_view; + auto h_numneigh = listcopy_kk->k_numneigh.h_view; + auto h_neighbors = listcopy_kk->k_neighbors.h_view; + + list->inum = inum; + list->gnum = gnum; + auto ilist = list->ilist; + auto numneigh = list->numneigh; + + // Kokkos neighbor data is stored differently than regular CPU, + // must copy element by element + + int *neighptr; + int **firstneigh = list->firstneigh; + MyPage *ipage = list->ipage; + ipage->reset(); + + for (int ii = 0; ii < inum_all; ii++) { + neighptr = ipage->vget(); + + const int i = h_ilist[ii]; + ilist[ii] = i; + + // loop over Kokkos neighbor list + + const int jnum = h_numneigh[i]; + numneigh[i] = jnum; + + for (int jj = 0; jj < jnum; jj++) { + const int joriginal = h_neighbors(i,jj); + neighptr[jj] = joriginal; + } + + firstneigh[i] = neighptr; + ipage->vgot(jnum); + if (ipage->status()) + error->one(FLERR,"Neighbor list overflow, boost neigh_modify one"); + } +} + namespace LAMMPS_NS { template class NPairCopyKokkos; #ifdef KOKKOS_ENABLE_CUDA diff --git a/src/KOKKOS/npair_copy_kokkos.h b/src/KOKKOS/npair_copy_kokkos.h index 84eb10b204..4bbb2749e5 100644 --- a/src/KOKKOS/npair_copy_kokkos.h +++ b/src/KOKKOS/npair_copy_kokkos.h @@ -36,6 +36,9 @@ class NPairCopyKokkos : public NPair { NPairCopyKokkos(class LAMMPS *); ~NPairCopyKokkos() {} void build(class NeighList *); + private: + void copy_to_kokkos(class NeighList *); + void copy_to_cpu(class NeighList *); }; } diff --git a/src/KOKKOS/npair_halffull_kokkos.cpp b/src/KOKKOS/npair_halffull_kokkos.cpp index cc8f663ef2..754a5ca010 100644 --- a/src/KOKKOS/npair_halffull_kokkos.cpp +++ b/src/KOKKOS/npair_halffull_kokkos.cpp @@ -68,12 +68,14 @@ void NPairHalffullKokkos::build(NeighList *list) copymode = 1; Kokkos::parallel_for(Kokkos::RangePolicy(0,inum_full),*this); + copymode = 0; list->inum = k_list_full->inum; list->gnum = k_list_full->gnum; - k_list->k_ilist.template modify(); - copymode = 0; + k_list->k_ilist.template modify(); + k_list->k_numneigh.template modify(); + k_list->k_neighbors.template modify(); } template diff --git a/src/KOKKOS/npair_kokkos.cpp b/src/KOKKOS/npair_kokkos.cpp index aa2a1fc5ff..8dce226ef0 100644 --- a/src/KOKKOS/npair_kokkos.cpp +++ b/src/KOKKOS/npair_kokkos.cpp @@ -273,7 +273,8 @@ void NPairKokkos::build(NeighList *list_) if(data.h_resize()) { list->maxneighs = data.h_new_maxneighs() * 1.2; - list->d_neighbors = typename ArrayTypes::t_neighbors_2d("neighbors", list->d_neighbors.extent(0), list->maxneighs); + list->k_neighbors = DAT::tdual_neighbors_2d("neighbors", list->d_neighbors.extent(0), list->maxneighs); + list->d_neighbors = list->k_neighbors.template view(); data.neigh_list.d_neighbors = list->d_neighbors; data.neigh_list.maxneighs = list->maxneighs; } @@ -288,6 +289,8 @@ void NPairKokkos::build(NeighList *list_) } list->k_ilist.template modify(); + list->k_numneigh.template modify(); + list->k_neighbors.template modify(); } /* ---------------------------------------------------------------------- */ diff --git a/src/KOKKOS/npair_ssa_kokkos.cpp b/src/KOKKOS/npair_ssa_kokkos.cpp index 5234c4e6d2..b5f892958b 100644 --- a/src/KOKKOS/npair_ssa_kokkos.cpp +++ b/src/KOKKOS/npair_ssa_kokkos.cpp @@ -519,6 +519,8 @@ fprintf(stdout, "Fina%03d %6d inum %6d gnum, total used %6d, allocated %6d\n" #endif list->k_ilist.template modify(); + list->k_numneigh.template modify(); + list->k_neighbors.template modify(); } diff --git a/src/neigh_list.cpp b/src/neigh_list.cpp index 1c53b2f7a4..c01f8ca595 100644 --- a/src/neigh_list.cpp +++ b/src/neigh_list.cpp @@ -80,6 +80,7 @@ NeighList::NeighList(LAMMPS *lmp) : Pointers(lmp) // Kokkos package kokkos = 0; + kk2cpu = 0; execution_space = Host; // USER-DPD package @@ -143,8 +144,11 @@ void NeighList::post_constructor(NeighRequest *nq) respainner = nq->respainner; copy = nq->copy; - if (nq->copy) + if (nq->copy) { listcopy = neighbor->lists[nq->copylist]; + if (listcopy->kokkos && !this->kokkos) + kk2cpu = 1; + } if (nq->skip) { listskip = neighbor->lists[nq->skiplist]; diff --git a/src/neigh_list.h b/src/neigh_list.h index 146a01e7b5..501188a724 100644 --- a/src/neigh_list.h +++ b/src/neigh_list.h @@ -42,6 +42,7 @@ class NeighList : protected Pointers { int respamiddle; // 1 if there is also a rRespa middle list int respainner; // 1 if there is also a rRespa inner list int copy; // 1 if this list is copied from another list + int kk2cpu; // 1 if this list is copied from Kokkos to CPU int copymode; // 1 if this is a Kokkos on-device copy // data structs to store neighbor pairs I,J and associated values diff --git a/src/neighbor.cpp b/src/neighbor.cpp index 3d1f37a03b..5783c24d2d 100644 --- a/src/neighbor.cpp +++ b/src/neighbor.cpp @@ -849,7 +849,8 @@ int Neighbor::init_pair() // allocate initial pages for each list, except if copy flag set for (i = 0; i < nlist; i++) { - if (lists[i]->copy) continue; + if (lists[i]->copy && !lists[i]->kk2cpu) + continue; lists[i]->setup_pages(pgsize,oneatom); } @@ -860,8 +861,10 @@ int Neighbor::init_pair() // also Kokkos list initialization int maxatom = atom->nmax; - for (i = 0; i < nlist; i++) - if (neigh_pair[i] && !lists[i]->copy) lists[i]->grow(maxatom,maxatom); + for (i = 0; i < nlist; i++) { + if (neigh_pair[i] && (!lists[i]->copy || lists[i]->kk2cpu)) + lists[i]->grow(maxatom,maxatom); + } // plist = indices of perpetual NPair classes // perpetual = non-occasional, re-built at every reneighboring @@ -1257,8 +1260,8 @@ void Neighbor::morph_copy() if (irq->history != jrq->history) continue; if (irq->bond != jrq->bond) continue; if (irq->intel != jrq->intel) continue; - if (irq->kokkos_host != jrq->kokkos_host) continue; - if (irq->kokkos_device != jrq->kokkos_device) continue; + if (irq->kokkos_host && !jrq->kokkos_host) continue; + if (irq->kokkos_device && !jrq->kokkos_device) continue; if (irq->ssa != jrq->ssa) continue; if (irq->cut != jrq->cut) continue; if (irq->cutoff != jrq->cutoff) continue; @@ -1789,8 +1792,12 @@ int Neighbor::choose_pair(NeighRequest *rq) if (rq->copy) { if (!(mask & NP_COPY)) continue; - if (!rq->kokkos_device != !(mask & NP_KOKKOS_DEVICE)) continue; - if (!rq->kokkos_host != !(mask & NP_KOKKOS_HOST)) continue; + if (rq->kokkos_device || rq->kokkos_host) { + if (!rq->kokkos_device != !(mask & NP_KOKKOS_DEVICE)) continue; + if (!rq->kokkos_host != !(mask & NP_KOKKOS_HOST)) continue; + } + if (!requests[rq->copylist]->kokkos_device != !(mask & NP_KOKKOS_DEVICE)) continue; + if (!requests[rq->copylist]->kokkos_host != !(mask & NP_KOKKOS_HOST)) continue; return i+1; } @@ -2102,7 +2109,8 @@ void Neighbor::build(int topoflag) for (i = 0; i < npair_perpetual; i++) { m = plist[i]; - if (!lists[m]->copy) lists[m]->grow(nlocal,nall); + if (!lists[i]->copy || lists[i]->kk2cpu) + lists[m]->grow(nlocal,nall); neigh_pair[m]->build_setup(); neigh_pair[m]->build(lists[m]); } @@ -2191,7 +2199,8 @@ void Neighbor::build_one(class NeighList *mylist, int preflag) // build the list - if (!mylist->copy) mylist->grow(atom->nlocal,atom->nlocal+atom->nghost); + if (!mylist->copy || mylist->kk2cpu) + mylist->grow(atom->nlocal,atom->nlocal+atom->nghost); np->build_setup(); np->build(mylist); } -- GitLab From c31917186ec6d5dd3be52a327df36c36c840b417 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 26 Feb 2020 14:34:42 -0700 Subject: [PATCH 041/577] Tweak error message --- src/KOKKOS/npair_copy_kokkos.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/KOKKOS/npair_copy_kokkos.cpp b/src/KOKKOS/npair_copy_kokkos.cpp index b0554db9ea..016d68400f 100644 --- a/src/KOKKOS/npair_copy_kokkos.cpp +++ b/src/KOKKOS/npair_copy_kokkos.cpp @@ -34,7 +34,7 @@ void NPairCopyKokkos::build(NeighList *list) if (list->kokkos) { if (!listcopy->kokkos) - error->all(FLERR,"Cannot copy non-Kokkos neighbor list to Kokkos neigh list"); + error->all(FLERR,"Cannot copy non-Kokkos neighbor list to Kokkos neighbor list"); copy_to_kokkos(list); } else { if (!listcopy->kokkos) -- GitLab From a739b8c6b766709a67265966753c9b401f9180af Mon Sep 17 00:00:00 2001 From: julient31 Date: Tue, 3 Mar 2020 07:32:13 -0700 Subject: [PATCH 042/577] Commit JT 030320 - modified fix/precession for correct mag energy calc. - reran all benchmark / examples in serial for verif - to do: rerun mpi examples, and clean code --- examples/SPIN/bfo/in.spin.bfo | 8 +- examples/SPIN/cobalt_fcc/in.spin.cobalt_fcc | 4 +- examples/SPIN/cobalt_hcp/in.spin.cobalt_hcp | 9 +- examples/SPIN/iron/in.spin.iron | 1 + examples/SPIN/nickel/in.spin.nickel | 3 +- examples/SPIN/nickel/in.spin.nickel_cubic | 2 +- examples/SPIN/read_restart/in.spin.read_data | 4 +- examples/SPIN/read_restart/in.spin.restart | 4 +- .../SPIN/read_restart/in.spin.write_restart | 3 +- examples/SPIN/run_spin_examples.sh | 2 +- examples/SPIN/run_spin_examples_serial.sh | 120 ++++++++++++++++++ examples/SPIN/setforce_spin/in.spin.setforce | 2 +- examples/SPIN/test_problems/README | 22 ++-- .../run-test-exchange.sh | 2 +- ...-precession.in => test-spin-precession.in} | 0 .../validation_damped_exchange/two_spins.data | 22 ++++ .../run-test-prec.sh | 2 +- ...-precession.in => test-spin-precession.in} | 1 + .../bench-prec-spin.in | 46 +++++++ .../run-test-prec.sh | 7 +- ...-spin.template => test-prec-spin.template} | 0 src/SPIN/compute_spin.cpp | 21 ++- src/SPIN/fix_precession_spin.cpp | 28 +++- src/SPIN/fix_precession_spin.h | 4 + src/SPIN/pair_spin.cpp | 2 +- 25 files changed, 272 insertions(+), 47 deletions(-) create mode 100755 examples/SPIN/run_spin_examples_serial.sh rename examples/SPIN/test_problems/validation_damped_exchange/{bench-spin-precession.in => test-spin-precession.in} (100%) create mode 100644 examples/SPIN/test_problems/validation_damped_exchange/two_spins.data rename examples/SPIN/test_problems/validation_damped_precession/{bench-spin-precession.in => test-spin-precession.in} (92%) create mode 100644 examples/SPIN/test_problems/validation_langevin_precession/bench-prec-spin.in rename examples/SPIN/test_problems/validation_langevin_precession/{bench-prec-spin.template => test-prec-spin.template} (100%) diff --git a/examples/SPIN/bfo/in.spin.bfo b/examples/SPIN/bfo/in.spin.bfo index b97f7e2d61..47ba535ab6 100644 --- a/examples/SPIN/bfo/in.spin.bfo +++ b/examples/SPIN/bfo/in.spin.bfo @@ -27,7 +27,8 @@ pair_coeff * * spin/dmi dmi 4.5 0.00005 1.0 1.0 1.0 neighbor 0.1 bin neigh_modify every 10 check yes delay 20 -fix 1 all precession/spin anisotropy 0.0000033 0.0 0.0 1.0 +fix 1 all precession/spin zeeman 0.0 0.0 0.0 1.0 anisotropy 0.00033 0.0 0.0 1.0 +fix_modify 1 energy yes fix 2 all langevin/spin 0.0 0.1 21 fix 3 all nve/spin lattice frozen @@ -43,9 +44,8 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -#thermo_style custom step time v_magnorm v_emag temp etotal -thermo_style custom step time v_magnorm pe ke v_emag temp etotal -thermo 10 +thermo_style custom step time v_magnorm pe v_emag temp etotal +thermo 50 compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 100 dump_bfo.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] diff --git a/examples/SPIN/cobalt_fcc/in.spin.cobalt_fcc b/examples/SPIN/cobalt_fcc/in.spin.cobalt_fcc index dd9ed890ee..f81a962e3f 100644 --- a/examples/SPIN/cobalt_fcc/in.spin.cobalt_fcc +++ b/examples/SPIN/cobalt_fcc/in.spin.cobalt_fcc @@ -45,8 +45,6 @@ compute out_pe all pe compute out_ke all ke compute out_temp all temp -thermo_style custom f_1 - variable magx equal c_out_mag[1] variable magy equal c_out_mag[2] variable magz equal c_out_mag[3] @@ -54,7 +52,7 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo_style custom step time f_1 v_magx v_magy v_magnorm v_emag temp etotal +thermo_style custom step time v_magx v_magy v_magnorm pe v_emag temp etotal thermo 50 # compute outsp all property/atom spx spy spz sp fmx fmy fmz diff --git a/examples/SPIN/cobalt_hcp/in.spin.cobalt_hcp b/examples/SPIN/cobalt_hcp/in.spin.cobalt_hcp index dd114202cb..2bfa8393f3 100644 --- a/examples/SPIN/cobalt_hcp/in.spin.cobalt_hcp +++ b/examples/SPIN/cobalt_hcp/in.spin.cobalt_hcp @@ -32,10 +32,9 @@ pair_coeff * * spin/exchange exchange 4.0 -0.3593 1.135028015e-05 1.064568567 neighbor 0.1 bin neigh_modify every 10 check yes delay 20 -#fix 1 all precession/spin zeeman 1.0 0.0 0.0 1.0 fix 1 all precession/spin anisotropy 0.01 0.0 0.0 1.0 -#fix 2 all langevin/spin 0.0 0.0 21 -fix 2 all langevin/spin 0.0 0.1 21 +fix_modify 1 energy yes +fix 2 all langevin/spin 0.0 0.0 21 fix 3 all nve/spin lattice moving timestep 0.0001 @@ -51,8 +50,8 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo_style custom step time v_magnorm v_emag temp press etotal -thermo 10 +thermo_style custom step time v_magnorm pe v_emag temp press etotal +thermo 50 compute outsp all property/atom spx spy spz sp fmx fmy fmz dump 1 all custom 100 dump_cobalt_hcp.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[3] diff --git a/examples/SPIN/iron/in.spin.iron b/examples/SPIN/iron/in.spin.iron index d60e6b86f5..58c0537af7 100644 --- a/examples/SPIN/iron/in.spin.iron +++ b/examples/SPIN/iron/in.spin.iron @@ -31,6 +31,7 @@ neighbor 0.1 bin neigh_modify every 10 check yes delay 20 fix 1 all precession/spin zeeman 0.0 0.0 0.0 1.0 +fix_modify 1 energy yes fix 2 all langevin/spin 0.0 0.0 21 fix 3 all nve/spin lattice moving diff --git a/examples/SPIN/nickel/in.spin.nickel b/examples/SPIN/nickel/in.spin.nickel index 1d62188d8f..0fd2e5f345 100644 --- a/examples/SPIN/nickel/in.spin.nickel +++ b/examples/SPIN/nickel/in.spin.nickel @@ -31,6 +31,7 @@ neighbor 0.1 bin neigh_modify every 10 check yes delay 20 fix 1 all precession/spin zeeman 0.0 0.0 0.0 1.0 +fix_modify 1 energy yes fix 2 all langevin/spin 0.0 0.0 21 fix 3 all nve/spin lattice moving @@ -48,7 +49,7 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo_style custom step time v_magnorm v_emag temp v_tmag etotal +thermo_style custom step time v_magnorm pe v_emag temp v_tmag etotal thermo 50 compute outsp all property/atom spx spy spz sp fmx fmy fmz diff --git a/examples/SPIN/nickel/in.spin.nickel_cubic b/examples/SPIN/nickel/in.spin.nickel_cubic index 1ae069a64f..88c477132e 100644 --- a/examples/SPIN/nickel/in.spin.nickel_cubic +++ b/examples/SPIN/nickel/in.spin.nickel_cubic @@ -50,7 +50,7 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo_style custom step time v_magnorm v_emag temp v_tmag etotal +thermo_style custom step time v_magnorm pe v_emag temp v_tmag etotal thermo 50 compute outsp all property/atom spx spy spz sp fmx fmy fmz diff --git a/examples/SPIN/read_restart/in.spin.read_data b/examples/SPIN/read_restart/in.spin.read_data index e788ecf67e..b2b55a9fcb 100644 --- a/examples/SPIN/read_restart/in.spin.read_data +++ b/examples/SPIN/read_restart/in.spin.read_data @@ -35,8 +35,8 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo 10 -thermo_style custom step time v_magnorm v_emag v_tmag temp etotal +thermo 20 +thermo_style custom step time v_magnorm pe v_emag v_tmag temp etotal thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz diff --git a/examples/SPIN/read_restart/in.spin.restart b/examples/SPIN/read_restart/in.spin.restart index ccce25b254..985da65eb4 100644 --- a/examples/SPIN/read_restart/in.spin.restart +++ b/examples/SPIN/read_restart/in.spin.restart @@ -39,8 +39,8 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo 10 -thermo_style custom step time v_magnorm v_emag v_tmag temp etotal +thermo 20 +thermo_style custom step time v_magnorm pe v_emag v_tmag temp etotal thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz diff --git a/examples/SPIN/read_restart/in.spin.write_restart b/examples/SPIN/read_restart/in.spin.write_restart index c127101093..19ab8e6b30 100644 --- a/examples/SPIN/read_restart/in.spin.write_restart +++ b/examples/SPIN/read_restart/in.spin.write_restart @@ -44,7 +44,7 @@ variable magnorm equal c_out_mag[4] variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] -thermo_style custom step time v_magnorm v_emag temp etotal +thermo_style custom step time v_magnorm pe v_emag temp etotal thermo 100 compute outsp all property/atom spx spy spz sp fmx fmy fmz @@ -52,4 +52,3 @@ dump 100 all custom 1 dump.lammpstrj type x y z c_outsp[1] c_outsp[2] c_outsp[ run 1000 write_restart restart_hcp_cobalt.equil - diff --git a/examples/SPIN/run_spin_examples.sh b/examples/SPIN/run_spin_examples.sh index a71da82a04..b2188503ee 100755 --- a/examples/SPIN/run_spin_examples.sh +++ b/examples/SPIN/run_spin_examples.sh @@ -1,6 +1,6 @@ #!/bin/bash -DATE=19Nov19 +DATE=21Fev20 # bfo cd bfo/ diff --git a/examples/SPIN/run_spin_examples_serial.sh b/examples/SPIN/run_spin_examples_serial.sh new file mode 100755 index 0000000000..f367dfd8f4 --- /dev/null +++ b/examples/SPIN/run_spin_examples_serial.sh @@ -0,0 +1,120 @@ +#!/bin/bash + +DATE=21Fev20 + +# bfo +cd bfo/ +../../../src/lmp_serial -in in.spin.bfo +cp log.lammps log.${DATE}.spin.bfo.g++.1 +../../../src/lmp_serial -in in.spin.bfo +cp log.lammps log.${DATE}.spin.bfo.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# fcc cobalt +cd cobalt_fcc/ +../../../src/lmp_serial -in in.spin.cobalt_fcc +cp log.lammps log.${DATE}.spin.cobalt_fcc.g++.1 +../../../src/lmp_serial -in in.spin.cobalt_fcc +cp log.lammps log.${DATE}.spin.cobalt_fcc.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# hcp cobalt +cd cobalt_hcp/ +../../../src/lmp_serial -in in.spin.cobalt_hcp +cp log.lammps log.${DATE}.spin.cobalt_hcp.g++.1 +../../../src/lmp_serial -in in.spin.cobalt_hcp +cp log.lammps log.${DATE}.spin.cobalt_hcp.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# dipole spin +cd dipole_spin/ +../../../src/lmp_serial -in in.spin.iron_dipole_cut +cp log.lammps log.${DATE}.spin.iron_dipole_cut.g++.1 +../../../src/lmp_serial -in in.spin.iron_dipole_cut +cp log.lammps log.${DATE}.spin.iron_dipole_cut.g++.4 +../../../src/lmp_serial -in in.spin.iron_dipole_ewald +cp log.lammps log.${DATE}.spin.iron_dipole_ewald.g++.1 +../../../src/lmp_serial -in in.spin.iron_dipole_ewald +cp log.lammps log.${DATE}.spin.iron_dipole_ewald.g++.4 +../../../src/lmp_serial -in in.spin.iron_dipole_pppm +cp log.lammps log.${DATE}.spin.iron_dipole_pppm.g++.1 +../../../src/lmp_serial -in in.spin.iron_dipole_pppm +cp log.lammps log.${DATE}.spin.iron_dipole_pppm.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# bcc iron +cd iron/ +../../../src/lmp_serial -in in.spin.iron +cp log.lammps log.${DATE}.spin.iron.g++.1 +../../../src/lmp_serial -in in.spin.iron +cp log.lammps log.${DATE}.spin.iron.g++.4 +../../../src/lmp_serial -in in.spin.iron_cubic +cp log.lammps log.${DATE}.spin.iron_cubic.g++.1 +../../../src/lmp_serial -in in.spin.iron_cubic +cp log.lammps log.${DATE}.spin.iron_cubic.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# fcc nickel +cd nickel/ +../../../src/lmp_serial -in in.spin.nickel +cp log.lammps log.${DATE}.spin.nickel.g++.1 +../../../src/lmp_serial -in in.spin.nickel +cp log.lammps log.${DATE}.spin.nickel.g++.4 +../../../src/lmp_serial -in in.spin.nickel_cubic +cp log.lammps log.${DATE}.spin.nickel_cubic.g++.1 +../../../src/lmp_serial -in in.spin.nickel_cubic +cp log.lammps log.${DATE}.spin.nickel_cubic.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# read restart +cd read_restart/ +../../../src/lmp_serial -in in.spin.write_restart +cp log.lammps log.${DATE}.spin.write_restart.g++.1 +../../../src/lmp_serial -in in.spin.write_restart +cp log.lammps log.${DATE}.spin.write_restart.g++.4 +../../../src/lmp_serial -in in.spin.restart +cp log.lammps log.${DATE}.spin.restart.g++.1 +../../../src/lmp_serial -in in.spin.restart +cp log.lammps log.${DATE}.spin.restart.g++.4 +../../../src/lmp_serial -in in.spin.read_data +cp log.lammps log.${DATE}.spin.read_data.g++.1 +../../../src/lmp_serial -in in.spin.read_data +cp log.lammps log.${DATE}.spin.read_data.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# setforce +cd setforce_spin/ +../../../src/lmp_serial -in in.spin.setforce +cp log.lammps log.${DATE}.spin.setforce.g++.1 +../../../src/lmp_serial -in in.spin.setforce +cp log.lammps log.${DATE}.spin.setforce.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. + +# spin minimizers +cd spinmin/ +../../../src/lmp_serial -in in.spin.bfo_min +cp log.lammps log.${DATE}.spin.bfo_min.g++.1 +../../../src/lmp_serial -in in.spin.bfo_min +cp log.lammps log.${DATE}.spin.bfo_min.g++.4 +../../../src/lmp_serial -in in.spin.bfo_min_cg +cp log.lammps log.${DATE}.spin.bfo_min_cg.g++.1 +../../../src/lmp_serial -in in.spin.bfo_min_cg +cp log.lammps log.${DATE}.spin.bfo_min_cg.g++.4 +../../../src/lmp_serial -in in.spin.bfo_min_lbfgs +cp log.lammps log.${DATE}.spin.bfo_min_lbfgs.g++.1 +../../../src/lmp_serial -in in.spin.bfo_min_lbfgs +cp log.lammps log.${DATE}.spin.bfo_min_lbfgs.g++.4 +../../../src/lmp_serial -in in.spin.iron_min +cp log.lammps log.${DATE}.spin.iron_min.g++.1 +../../../src/lmp_serial -in in.spin.iron_min +cp log.lammps log.${DATE}.spin.iron_min.g++.4 +rm log.lammps log.cite dump*.lammpstrj +cd .. diff --git a/examples/SPIN/setforce_spin/in.spin.setforce b/examples/SPIN/setforce_spin/in.spin.setforce index 0d65955a29..4edf70eb52 100644 --- a/examples/SPIN/setforce_spin/in.spin.setforce +++ b/examples/SPIN/setforce_spin/in.spin.setforce @@ -48,7 +48,7 @@ variable emag equal c_out_mag[5] variable tmag equal c_out_mag[6] thermo 100 -thermo_style custom step time v_magx v_magz v_magnorm v_tmag etotal +thermo_style custom step time v_magx v_magz v_magnorm v_tmag pe v_emag etotal thermo_modify format float %20.15g compute outsp all property/atom spx spy spz sp fmx fmy fmz diff --git a/examples/SPIN/test_problems/README b/examples/SPIN/test_problems/README index 5557e3d42b..0a1362ec9c 100644 --- a/examples/SPIN/test_problems/README +++ b/examples/SPIN/test_problems/README @@ -1,4 +1,4 @@ -** The objective of the benchmark examples in this directory +** The objective of the test problems in this directory is the following twofold: - verify the implementation of the LAMMPS' SPIN package by comparing its results to well-known analytic results, or @@ -6,39 +6,39 @@ - provide users with simple comparisons, allowing them to better understand what is implemented in the code. -The LAMMPS input file (bench-*) can be modified, as well as the +The LAMMPS input file (test-*) can be modified, as well as the associated python script, in order to try different comparisons. All scripts can be run by executing the shell script from its directory. Example: -./run-bench-exchange.sh from the benchmarck_damped_exchange/ +./run-test-exchange.sh from the validation_damped_exchange/ directory. -** Below a brief description of the different benchmark +** Below a brief description of the different validation problems: -- benchmarck_damped_precession: +- validation_damped_precession: simulates the damped precession of a single spin in a magnetic field. - Run as: ./run-bench-prec.sh + Run as: ./run-test-prec.sh Output: x, y and z components of the magnetization, and magnetic energy. -- benchmarck_damped_exchange: +- validation_damped_exchange: simulates two spins interacting through the exchange interaction. The parameters in the LAMMPS input script - (bench-spin-precession.in) are calibrated to match the + (test-spin-precession.in) are calibrated to match the exchange definition in the python script (llg_exchange.py). - Run as: ./run-bench-exchange.sh + Run as: ./run-test-exchange.sh Output: average magnetization resulting from the damped precession of the two interacting spins. Also plots the evolution of the magnetic energy. -- benchmarck_langevin_precession: +- validation_langevin_precession: simulates a single spin in a magnetic field and in contact with a thermal bath, and compares the statistical averages of the output to the analytical result of the Langevin function. - Run as: ./run-bench-prec.sh + Run as: ./run-test-prec.sh Output: statistical average of the z-component of the magnetization (along the applied field) and of the magnetic energy versus temperature. Comparison to the Langevin function diff --git a/examples/SPIN/test_problems/validation_damped_exchange/run-test-exchange.sh b/examples/SPIN/test_problems/validation_damped_exchange/run-test-exchange.sh index 15de8d350e..599730fe7b 100755 --- a/examples/SPIN/test_problems/validation_damped_exchange/run-test-exchange.sh +++ b/examples/SPIN/test_problems/validation_damped_exchange/run-test-exchange.sh @@ -5,7 +5,7 @@ rm res_*.dat # compute Lammps ./../../../../src/lmp_serial \ - -in bench-spin-precession.in + -in test-spin-precession.in in="$(grep -n Step log.lammps | awk -F ':' '{print $1}')" en="$(grep -n Loop log.lammps | awk -F ':' '{print $1}')" in="$(echo "$in+1" | bc -l)" diff --git a/examples/SPIN/test_problems/validation_damped_exchange/bench-spin-precession.in b/examples/SPIN/test_problems/validation_damped_exchange/test-spin-precession.in similarity index 100% rename from examples/SPIN/test_problems/validation_damped_exchange/bench-spin-precession.in rename to examples/SPIN/test_problems/validation_damped_exchange/test-spin-precession.in diff --git a/examples/SPIN/test_problems/validation_damped_exchange/two_spins.data b/examples/SPIN/test_problems/validation_damped_exchange/two_spins.data new file mode 100644 index 0000000000..013f813751 --- /dev/null +++ b/examples/SPIN/test_problems/validation_damped_exchange/two_spins.data @@ -0,0 +1,22 @@ +LAMMPS data file via write_data, version 19 Sep 2019, timestep = 0 + +2 atoms +1 atom types + +0.0 6.0 xlo xhi +0.0 3.0 ylo yhi +0.0 3.0 zlo zhi + +Masses + +1 1 + +Atoms # spin + +1 1 2.0 0.0 0.0 0.0 1.0 0.0 0.0 0 0 0 +2 1 2.0 3.0 0.0 0.0 0.0 1.0 0.0 0 0 0 + +Velocities + +1 0.0 0.0 0.0 +2 0.0 0.0 0.0 diff --git a/examples/SPIN/test_problems/validation_damped_precession/run-test-prec.sh b/examples/SPIN/test_problems/validation_damped_precession/run-test-prec.sh index 49ebc2ac4e..e21f28521a 100755 --- a/examples/SPIN/test_problems/validation_damped_precession/run-test-prec.sh +++ b/examples/SPIN/test_problems/validation_damped_precession/run-test-prec.sh @@ -5,7 +5,7 @@ rm res_*.dat # compute Lammps ./../../../../src/lmp_serial \ - -in bench-spin-precession.in + -in test-spin-precession.in in="$(grep -n Step log.lammps | awk -F ':' '{print $1}')" en="$(grep -n Loop log.lammps | awk -F ':' '{print $1}')" in="$(echo "$in+1" | bc -l)" diff --git a/examples/SPIN/test_problems/validation_damped_precession/bench-spin-precession.in b/examples/SPIN/test_problems/validation_damped_precession/test-spin-precession.in similarity index 92% rename from examples/SPIN/test_problems/validation_damped_precession/bench-spin-precession.in rename to examples/SPIN/test_problems/validation_damped_precession/test-spin-precession.in index ed8a5caeaf..6722e2a5ed 100644 --- a/examples/SPIN/test_problems/validation_damped_precession/bench-spin-precession.in +++ b/examples/SPIN/test_problems/validation_damped_precession/test-spin-precession.in @@ -26,6 +26,7 @@ variable Temperature equal 0.0 variable Nsteps equal 500000 fix 1 all nve/spin lattice no +# fix 2 all precession/spin zeeman ${H} 0.0 0.0 1.0 anisotropy ${Kan} 0.0 0.0 1.0 fix 2 all precession/spin zeeman ${H} 0.0 0.0 1.0 anisotropy ${Kan} 0.0 0.0 1.0 fix_modify 2 energy yes fix 3 all langevin/spin ${Temperature} 0.01 12345 diff --git a/examples/SPIN/test_problems/validation_langevin_precession/bench-prec-spin.in b/examples/SPIN/test_problems/validation_langevin_precession/bench-prec-spin.in new file mode 100644 index 0000000000..45da087477 --- /dev/null +++ b/examples/SPIN/test_problems/validation_langevin_precession/bench-prec-spin.in @@ -0,0 +1,46 @@ +#LAMMPS in.run + +units metal +atom_style spin +atom_modify map array +boundary p p p + +# read_data singlespin.data + +lattice sc 3.0 +region box block 0.0 1.0 0.0 1.0 0.0 1.0 +create_box 1 box +create_atoms 1 box + +mass 1 1.0 +set type 1 spin 1.0 0.0 0.0 1.0 + +# defines a pair/style for neighbor list, but do not use it +pair_style spin/exchange 4.0 +pair_coeff * * exchange 1.0 0.0 0.0 1.0 + +group bead type 1 + +variable H equal 10.0 +variable Kan equal 0.0 +variable Temperature equal 19.00000000000000000000 +variable RUN equal 1000000 + +fix 1 all nve/spin lattice no +fix 2 all precession/spin zeeman ${H} 0.0 0.0 1.0 anisotropy ${Kan} 0.0 0.0 1.0 +fix_modify 2 energy yes +fix 3 all langevin/spin ${Temperature} 0.01 12345 + +compute compute_spin all spin +compute outsp all property/atom spx spy spz sp +compute magsz all reduce ave c_outsp[3] + +thermo 50000 +thermo_style custom step time temp vol pe c_compute_spin[5] etotal + +variable magnetic_energy equal c_compute_spin[5] + +fix avespin all ave/time 1 ${RUN} ${RUN} v_Temperature v_H v_Kan c_magsz v_magnetic_energy file average_spin + +timestep 0.1 +run ${RUN} diff --git a/examples/SPIN/test_problems/validation_langevin_precession/run-test-prec.sh b/examples/SPIN/test_problems/validation_langevin_precession/run-test-prec.sh index 98fceeca95..2427e20095 100755 --- a/examples/SPIN/test_problems/validation_langevin_precession/run-test-prec.sh +++ b/examples/SPIN/test_problems/validation_langevin_precession/run-test-prec.sh @@ -10,10 +10,9 @@ N=20 for (( i=0; i<$N; i++ )) do temp="$(echo "$tempi+$i*($tempf-$tempi)/$N" | bc -l)" - sed s/temperature/${temp}/g bench-prec-spin.template > \ - bench-prec-spin.in - ./../../../../src/lmp_serial \ - -in bench-prec-spin.in + sed s/temperature/${temp}/g test-prec-spin.template > \ + test-prec-spin.in + ./../../../../src/lmp_serial -in test-prec-spin.in Hz="$(tail -n 1 average_spin | awk -F " " '{print $3}')" sz="$(tail -n 1 average_spin | awk -F " " '{print $5}')" en="$(tail -n 1 average_spin | awk -F " " '{print $6}')" diff --git a/examples/SPIN/test_problems/validation_langevin_precession/bench-prec-spin.template b/examples/SPIN/test_problems/validation_langevin_precession/test-prec-spin.template similarity index 100% rename from examples/SPIN/test_problems/validation_langevin_precession/bench-prec-spin.template rename to examples/SPIN/test_problems/validation_langevin_precession/test-prec-spin.template diff --git a/src/SPIN/compute_spin.cpp b/src/SPIN/compute_spin.cpp index 8a71be019b..9a759134b4 100644 --- a/src/SPIN/compute_spin.cpp +++ b/src/SPIN/compute_spin.cpp @@ -41,13 +41,20 @@ using namespace MathConst; /* ---------------------------------------------------------------------- */ ComputeSpin::ComputeSpin(LAMMPS *lmp, int narg, char **arg) : - Compute(lmp, narg, arg) + Compute(lmp, narg, arg), pair(NULL), spin_pairs(NULL) { if ((narg != 3) && (narg != 4)) error->all(FLERR,"Illegal compute compute/spin command"); vector_flag = 1; size_vector = 6; extvector = 0; + // npairs = npairspin = 0; + + // initialize the magnetic interaction flags + + pair_spin_flag = 0; + long_spin_flag = 0; + precession_spin_flag = 0; init(); @@ -60,6 +67,7 @@ ComputeSpin::ComputeSpin(LAMMPS *lmp, int narg, char **arg) : ComputeSpin::~ComputeSpin() { memory->destroy(vector); + delete [] spin_pairs; } /* ---------------------------------------------------------------------- */ @@ -68,7 +76,11 @@ void ComputeSpin::init() { hbar = force->hplanck/MY_2PI; kb = force->boltz; + npairs = npairspin = 0; + precession_spin_flag = 0; + // set ptrs on Pair/Spin styles + // loop 1: obtain # of Pairs, and # of Pair/Spin styles if (force->pair_match("spin",0,0)) { // only one Pair/Spin style @@ -173,9 +185,10 @@ void ComputeSpin::compute_vector() // update magnetic precession energies if (precession_spin_flag) { - magenergy -= lockprecessionspin->compute_zeeman_energy(sp[i]); - magenergy -= lockprecessionspin->compute_anisotropy_energy(sp[i]); - magenergy -= lockprecessionspin->compute_cubic_energy(sp[i]); + magenergy += lockprecessionspin->emag[i]; + // magenergy -= lockprecessionspin->compute_zeeman_energy(sp[i]); + // magenergy -= lockprecessionspin->compute_anisotropy_energy(sp[i]); + // magenergy -= lockprecessionspin->compute_cubic_energy(sp[i]); } // update magnetic pair interactions diff --git a/src/SPIN/fix_precession_spin.cpp b/src/SPIN/fix_precession_spin.cpp index 57e4549718..ffe3fc838c 100644 --- a/src/SPIN/fix_precession_spin.cpp +++ b/src/SPIN/fix_precession_spin.cpp @@ -30,6 +30,7 @@ #include "force.h" #include "input.h" #include "math_const.h" +#include "memory.h" #include "modify.h" #include "respa.h" #include "update.h" @@ -43,7 +44,7 @@ enum{CONSTANT,EQUAL}; /* ---------------------------------------------------------------------- */ -FixPrecessionSpin::FixPrecessionSpin(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) +FixPrecessionSpin::FixPrecessionSpin(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), emag(NULL) { if (narg < 7) error->all(FLERR,"Illegal precession/spin command"); @@ -154,6 +155,9 @@ FixPrecessionSpin::FixPrecessionSpin(LAMMPS *lmp, int narg, char **arg) : Fix(lm FixPrecessionSpin::~FixPrecessionSpin() { delete [] magstr; + + // test emag list storing mag energies + memory->destroy(emag); } /* ---------------------------------------------------------------------- */ @@ -213,6 +217,11 @@ void FixPrecessionSpin::init() if (varflag == CONSTANT) set_magneticprecession(); + // test emag list storing mag energies + // init. size of energy stacking lists + + nlocal_max = atom->nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); } /* ---------------------------------------------------------------------- */ @@ -252,21 +261,33 @@ void FixPrecessionSpin::post_force(int /* vflag */) double **fm = atom->fm; double **sp = atom->sp; const int nlocal = atom->nlocal; - double spi[3], fmi[3], epreci; + double spi[4], fmi[3], epreci; + // test emag list storing mag energies + // checking size of emag + if (nlocal_max < nlocal) { // grow emag lists if necessary + nlocal_max = nlocal; + memory->grow(emag,nlocal_max,"pair/spin:emag"); + } + eflag = 0; eprec = 0.0; for (int i = 0; i < nlocal; i++) { + + // test emag list storing mag energies + emag[i] = 0.0; + if (mask[i] & groupbit) { epreci = 0.0; spi[0] = sp[i][0]; spi[1] = sp[i][1]; spi[2] = sp[i][2]; + spi[3] = sp[i][3]; fmi[0] = fmi[1] = fmi[2] = 0.0; if (zeeman_flag) { // compute Zeeman interaction compute_zeeman(i,fmi); - epreci -= hbar*(spi[0]*fmi[0] + spi[1]*fmi[1] + spi[2]*fmi[2]); + epreci -= compute_zeeman_energy(spi); } if (aniso_flag) { // compute magnetic anisotropy @@ -279,6 +300,7 @@ void FixPrecessionSpin::post_force(int /* vflag */) epreci -= compute_cubic_energy(spi); } + emag[i] += epreci; eprec += epreci; fm[i][0] += fmi[0]; fm[i][1] += fmi[1]; diff --git a/src/SPIN/fix_precession_spin.h b/src/SPIN/fix_precession_spin.h index 3c809506c1..7767864655 100644 --- a/src/SPIN/fix_precession_spin.h +++ b/src/SPIN/fix_precession_spin.h @@ -57,6 +57,10 @@ class FixPrecessionSpin : public Fix { void compute_cubic(double *, double *); double compute_cubic_energy(double *); + // test emag list storing mag energies + int nlocal_max; // max value of nlocal (for size of lists) + double *emag; // energy list + protected: int style; // style of the magnetic precession diff --git a/src/SPIN/pair_spin.cpp b/src/SPIN/pair_spin.cpp index 01b8775eab..112f404bc0 100644 --- a/src/SPIN/pair_spin.cpp +++ b/src/SPIN/pair_spin.cpp @@ -42,7 +42,7 @@ using namespace MathConst; /* ---------------------------------------------------------------------- */ -PairSpin::PairSpin(LAMMPS *lmp) : Pair(lmp) +PairSpin::PairSpin(LAMMPS *lmp) : Pair(lmp), emag(NULL) { hbar = force->hplanck/MY_2PI; single_enable = 0; -- GitLab From 72a9ce0f323f00375cfaed51df0c868c2e21eaff Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 4 Mar 2020 12:31:37 -0700 Subject: [PATCH 043/577] Add loop chunking option to compute_orientorder_atom_kokkos --- .../compute_orientorder_atom_kokkos.cpp | 173 ++++++++++-------- src/KOKKOS/compute_orientorder_atom_kokkos.h | 2 +- src/compute_orientorder_atom.cpp | 8 + src/compute_orientorder_atom.h | 1 + 4 files changed, 105 insertions(+), 79 deletions(-) diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp index 65bb08b18d..a4a4451197 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp @@ -130,9 +130,6 @@ void ComputeOrientOrderAtomKokkos::compute_peratom() d_neighbors = k_list->d_neighbors; d_ilist = k_list->d_ilist; - maxneigh = 0; - Kokkos::parallel_reduce("ComputeOrientOrderAtomKokkos::find_max_neighs",inum, FindMaxNumNeighs(k_list), Kokkos::Experimental::Max(maxneigh)); - // grow order parameter array if necessary if (atom->nmax > nmax) { @@ -141,21 +138,29 @@ void ComputeOrientOrderAtomKokkos::compute_peratom() memoryKK->create_kokkos(k_qnarray,qnarray,nmax,ncol,"orientorder/atom:qnarray"); array_atom = qnarray; d_qnarray = k_qnarray.template view(); + } - d_qnm = t_sna_3c("orientorder/atom:qnm",nmax,nqlist,2*qmax+1); - d_ncount = t_sna_1i("orientorder/atom:ncount",nmax); + chunk_size = MIN(chunksize,inum); // "chunksize" variable is set by user + chunk_offset = 0; - // insure distsq and nearest arrays are long enough - - if (maxneigh > d_distsq.extent(1)) { - d_distsq = t_sna_2d_lr("orientorder/atom:distsq",nmax,maxneigh); - d_nearest = t_sna_2i_lr("orientorder/atom:nearest",nmax,maxneigh); - d_rlist = t_sna_3d_lr("orientorder/atom:rlist",nmax,maxneigh,3); - - d_distsq_um = d_distsq; - d_rlist_um = d_rlist; - d_nearest_um = d_nearest; - } + if (chunk_size > d_ncount.extent(0)) { + d_qnm = t_sna_3c("orientorder/atom:qnm",chunk_size,nqlist,2*qmax+1); + d_ncount = t_sna_1i("orientorder/atom:ncount",chunk_size); + } + + // insure distsq and nearest arrays are long enough + + maxneigh = 0; + Kokkos::parallel_reduce("ComputeOrientOrderAtomKokkos::find_max_neighs",inum, FindMaxNumNeighs(k_list), Kokkos::Experimental::Max(maxneigh)); + + if (chunk_size > d_distsq.extent(0) || maxneigh > d_distsq.extent(1)) { + d_distsq = t_sna_2d_lr("orientorder/atom:distsq",nmax,maxneigh); + d_nearest = t_sna_2i_lr("orientorder/atom:nearest",nmax,maxneigh); + d_rlist = t_sna_3d_lr("orientorder/atom:rlist",nmax,maxneigh,3); + + d_distsq_um = d_distsq; + d_rlist_um = d_rlist; + d_nearest_um = d_nearest; } // compute order parameter for each atom in group @@ -178,21 +183,29 @@ void ComputeOrientOrderAtomKokkos::compute_peratom() copymode = 1; - //Neigh - typename Kokkos::TeamPolicy policy_neigh(inum,team_size,vector_length); - Kokkos::parallel_for("ComputeOrientOrderAtomNeigh",policy_neigh,*this); + while (chunk_offset < inum) { // chunk up loop to prevent running out of memory - //Select3 - typename Kokkos::RangePolicy policy_select3(0,inum); - Kokkos::parallel_for("ComputeOrientOrderAtomSelect3",policy_select3,*this); + if (chunk_size > inum - chunk_offset) + chunk_size = inum - chunk_offset; - //BOOP1 - typename Kokkos::TeamPolicy policy_boop1(((inum+team_size-1)/team_size)*maxneigh,team_size,vector_length); - Kokkos::parallel_for("ComputeOrientOrderAtomBOOP1",policy_boop1,*this); + //Neigh + typename Kokkos::TeamPolicy policy_neigh(chunk_size,team_size,vector_length); + Kokkos::parallel_for("ComputeOrientOrderAtomNeigh",policy_neigh,*this); + + //Select3 + typename Kokkos::RangePolicy policy_select3(0,chunk_size); + Kokkos::parallel_for("ComputeOrientOrderAtomSelect3",policy_select3,*this); + + //BOOP1 + typename Kokkos::TeamPolicy policy_boop1(((chunk_size+team_size-1)/team_size)*maxneigh,team_size,vector_length); + Kokkos::parallel_for("ComputeOrientOrderAtomBOOP1",policy_boop1,*this); + + //BOOP2 + typename Kokkos::RangePolicy policy_boop2(0,chunk_size); + Kokkos::parallel_for("ComputeOrientOrderAtomBOOP2",policy_boop2,*this); - //BOOP2 - typename Kokkos::RangePolicy policy_boop2(0,inum); - Kokkos::parallel_for("ComputeOrientOrderAtomBOOP2",policy_boop2,*this); + chunk_offset += chunk_size; + } // end while copymode = 0; @@ -207,7 +220,7 @@ KOKKOS_INLINE_FUNCTION void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomNeigh,const typename Kokkos::TeamPolicy::member_type& team) const { const int ii = team.league_rank(); - const int i = d_ilist[ii]; + const int i = d_ilist[ii + chunk_offset]; if (mask[i] & groupbit) { const X_FLOAT xtmp = x(i,0); const X_FLOAT ytmp = x(i,1); @@ -263,7 +276,7 @@ template KOKKOS_INLINE_FUNCTION void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomSelect3,const int& ii) const { - const int i = d_ilist[ii]; + const int i = d_ilist[ii + chunk_offset]; const int ncount = d_ncount(ii); // if not nnn neighbors, order parameter = 0; @@ -287,11 +300,12 @@ KOKKOS_INLINE_FUNCTION void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomBOOP1,const typename Kokkos::TeamPolicy::member_type& team) const { // Extract the atom number - int ii = team.team_rank() + team.team_size() * (team.league_rank() % ((inum+team.team_size()-1)/team.team_size())); - if (ii >= inum) return; + int ii = team.team_rank() + team.team_size() * (team.league_rank() % + ((chunk_size+team.team_size()-1)/team.team_size())); + if (ii >= chunk_size) return; // Extract the neighbor number - const int jj = team.league_rank() / ((inum+team.team_size()-1)/team.team_size()); + const int jj = team.league_rank() / ((chunk_size+team.team_size()-1)/team.team_size()); const int ncount = d_ncount(ii); if (jj >= ncount) return; @@ -306,7 +320,6 @@ void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrder template KOKKOS_INLINE_FUNCTION void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrderAtomBOOP2,const int& ii) const { - const int i = d_ilist[ii]; const int ncount = d_ncount(ii); calc_boop2(ncount, ii); } @@ -338,14 +351,14 @@ void ComputeOrientOrderAtomKokkos::operator() (TagComputeOrientOrder template KOKKOS_INLINE_FUNCTION -void ComputeOrientOrderAtomKokkos::select3(int k, int n, int iatom) const +void ComputeOrientOrderAtomKokkos::select3(int k, int n, int ii) const { int i,ir,j,l,mid,ia,itmp; double a,tmp,a3[3]; - auto arr = Kokkos::subview(d_distsq_um, iatom, Kokkos::ALL); - auto iarr = Kokkos::subview(d_nearest_um, iatom, Kokkos::ALL); - auto arr3 = Kokkos::subview(d_rlist_um, iatom, Kokkos::ALL, Kokkos::ALL); + auto arr = Kokkos::subview(d_distsq_um, ii, Kokkos::ALL); + auto iarr = Kokkos::subview(d_nearest_um, ii, Kokkos::ALL); + auto arr3 = Kokkos::subview(d_rlist_um, ii, Kokkos::ALL, Kokkos::ALL); l = 0; ir = n-1; @@ -414,11 +427,13 @@ void ComputeOrientOrderAtomKokkos::select3(int k, int n, int iatom) template KOKKOS_INLINE_FUNCTION -void ComputeOrientOrderAtomKokkos::calc_boop1(int ncount, int iatom, int ineigh) const +void ComputeOrientOrderAtomKokkos::calc_boop1(int ncount, int ii, int ineigh) const { - const double r0 = d_rlist(iatom,ineigh,0); - const double r1 = d_rlist(iatom,ineigh,1); - const double r2 = d_rlist(iatom,ineigh,2); + const int i = d_ilist[ii + chunk_offset]; + + const double r0 = d_rlist(ii,ineigh,0); + const double r1 = d_rlist(ii,ineigh,1); + const double r2 = d_rlist(ii,ineigh,2); const double rmag = sqrt(r0*r0 + r1*r1 + r2*r2); if(rmag <= MY_EPSILON) { return; @@ -439,27 +454,27 @@ void ComputeOrientOrderAtomKokkos::calc_boop1(int ncount, int iatom, for (int il = 0; il < nqlist; il++) { const int l = d_qlist[il]; - //d_qnm(iatom,il,l).re += polar_prefactor(l, 0, costheta); + //d_qnm(ii,il,l).re += polar_prefactor(l, 0, costheta); const double polar_pf = polar_prefactor(l, 0, costheta); - Kokkos::atomic_add(&(d_qnm(iatom,il,l).re), polar_pf); + Kokkos::atomic_add(&(d_qnm(ii,il,l).re), polar_pf); SNAcomplex expphim = {expphi.re,expphi.im}; for(int m = 1; m <= +l; m++) { const double prefactor = polar_prefactor(l, m, costheta); SNAcomplex c = {prefactor * expphim.re, prefactor * expphim.im}; - //d_qnm(iatom,il,m+l).re += c.re; - //d_qnm(iatom,il,m+l).im += c.im; - Kokkos::atomic_add(&(d_qnm(iatom,il,m+l).re), c.re); - Kokkos::atomic_add(&(d_qnm(iatom,il,m+l).im), c.im); + //d_qnm(ii,il,m+l).re += c.re; + //d_qnm(ii,il,m+l).im += c.im; + Kokkos::atomic_add(&(d_qnm(ii,il,m+l).re), c.re); + Kokkos::atomic_add(&(d_qnm(ii,il,m+l).im), c.im); if(m & 1) { - //d_qnm(iatom,il,-m+l).re -= c.re; - //d_qnm(iatom,il,-m+l).im += c.im; - Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).re), -c.re); - Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).im), c.im); + //d_qnm(ii,il,-m+l).re -= c.re; + //d_qnm(ii,il,-m+l).im += c.im; + Kokkos::atomic_add(&(d_qnm(ii,il,-m+l).re), -c.re); + Kokkos::atomic_add(&(d_qnm(ii,il,-m+l).im), c.im); } else { - //d_qnm(iatom,il,-m+l).re += c.re; - //d_qnm(iatom,il,-m+l).im -= c.im; - Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).re), c.re); - Kokkos::atomic_add(&(d_qnm(iatom,il,-m+l).im), -c.im); + //d_qnm(ii,il,-m+l).re += c.re; + //d_qnm(ii,il,-m+l).im -= c.im; + Kokkos::atomic_add(&(d_qnm(ii,il,-m+l).re), c.re); + Kokkos::atomic_add(&(d_qnm(ii,il,-m+l).im), -c.im); } SNAcomplex tmp; tmp.re = expphim.re*expphi.re - expphim.im*expphi.im; @@ -476,16 +491,18 @@ void ComputeOrientOrderAtomKokkos::calc_boop1(int ncount, int iatom, template KOKKOS_INLINE_FUNCTION -void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int iatom) const +void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int ii) const { + const int i = d_ilist[ii + chunk_offset]; + // convert sums to averages double facn = 1.0 / ncount; for (int il = 0; il < nqlist; il++) { int l = d_qlist[il]; for(int m = 0; m < 2*l+1; m++) { - d_qnm(iatom,il,m).re *= facn; - d_qnm(iatom,il,m).im *= facn; + d_qnm(ii,il,m).re *= facn; + d_qnm(ii,il,m).im *= facn; } } @@ -498,8 +515,8 @@ void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int iatom) double qnormfac = sqrt(MY_4PI/(2*l+1)); double qm_sum = 0.0; for(int m = 0; m < 2*l+1; m++) - qm_sum += d_qnm(iatom,il,m).re*d_qnm(iatom,il,m).re + d_qnm(iatom,il,m).im*d_qnm(iatom,il,m).im; - d_qnarray(iatom,jj++) = qnormfac * sqrt(qm_sum); + qm_sum += d_qnm(ii,il,m).re*d_qnm(ii,il,m).re + d_qnm(ii,il,m).im*d_qnm(ii,il,m).im; + d_qnarray(i,jj++) = qnormfac * sqrt(qm_sum); } // calculate W_l @@ -513,13 +530,13 @@ void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int iatom) for(int m2 = MAX(0,l-m1); m2 < MIN(2*l+1,3*l-m1+1); m2++) { int m = m1 + m2 - l; SNAcomplex qm1qm2; - qm1qm2.re = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).re - d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).im; - qm1qm2.im = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).im + d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).re; - wlsum += (qm1qm2.re*d_qnm(iatom,il,m).re + qm1qm2.im*d_qnm(iatom,il,m).im)*d_cglist[idxcg_count]; + qm1qm2.re = d_qnm(ii,il,m1).re*d_qnm(ii,il,m2).re - d_qnm(ii,il,m1).im*d_qnm(ii,il,m2).im; + qm1qm2.im = d_qnm(ii,il,m1).re*d_qnm(ii,il,m2).im + d_qnm(ii,il,m1).im*d_qnm(ii,il,m2).re; + wlsum += (qm1qm2.re*d_qnm(ii,il,m).re + qm1qm2.im*d_qnm(ii,il,m).im)*d_cglist[idxcg_count]; idxcg_count++; } } - d_qnarray(iatom,jj++) = wlsum/sqrt(2.0*l+1.0); + d_qnarray(i,jj++) = wlsum/sqrt(2.0*l+1.0); } } @@ -534,19 +551,19 @@ void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int iatom) for(int m2 = MAX(0,l-m1); m2 < MIN(2*l+1,3*l-m1+1); m2++) { const int m = m1 + m2 - l; SNAcomplex qm1qm2; - qm1qm2.re = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).re - d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).im; - qm1qm2.im = d_qnm(iatom,il,m1).re*d_qnm(iatom,il,m2).im + d_qnm(iatom,il,m1).im*d_qnm(iatom,il,m2).re; - wlsum += (qm1qm2.re*d_qnm(iatom,il,m).re + qm1qm2.im*d_qnm(iatom,il,m).im)*d_cglist[idxcg_count]; + qm1qm2.re = d_qnm(ii,il,m1).re*d_qnm(ii,il,m2).re - d_qnm(ii,il,m1).im*d_qnm(ii,il,m2).im; + qm1qm2.im = d_qnm(ii,il,m1).re*d_qnm(ii,il,m2).im + d_qnm(ii,il,m1).im*d_qnm(ii,il,m2).re; + wlsum += (qm1qm2.re*d_qnm(ii,il,m).re + qm1qm2.im*d_qnm(ii,il,m).im)*d_cglist[idxcg_count]; idxcg_count++; } } // Whats = [w/(q/np.sqrt(np.pi * 4 / (2 * l + 1)))**3 if abs(q) > 1.0e-6 else 0.0 for l,q,w in zip(range(1,max_l+1),Qs,Ws)] - if (d_qnarray(iatom,il) < QEPSILON) - d_qnarray(iatom,jj++) = 0.0; + if (d_qnarray(i,il) < QEPSILON) + d_qnarray(i,jj++) = 0.0; else { const double qnormfac = sqrt(MY_4PI/(2*l+1)); - const double qnfac = qnormfac/d_qnarray(iatom,il); - d_qnarray(iatom,jj++) = wlsum/sqrt(2.0*l+1.0)*(qnfac*qnfac*qnfac); + const double qnfac = qnormfac/d_qnarray(i,il); + d_qnarray(i,jj++) = wlsum/sqrt(2.0*l+1.0)*(qnfac*qnfac*qnfac); } } } @@ -556,17 +573,17 @@ void ComputeOrientOrderAtomKokkos::calc_boop2(int ncount, int iatom) if (qlcompflag) { const int il = iqlcomp; const int l = qlcomp; - if (d_qnarray(iatom,il) < QEPSILON) + if (d_qnarray(i,il) < QEPSILON) for(int m = 0; m < 2*l+1; m++) { - d_qnarray(iatom,jj++) = 0.0; - d_qnarray(iatom,jj++) = 0.0; + d_qnarray(i,jj++) = 0.0; + d_qnarray(i,jj++) = 0.0; } else { const double qnormfac = sqrt(MY_4PI/(2*l+1)); - const double qnfac = qnormfac/d_qnarray(iatom,il); + const double qnfac = qnormfac/d_qnarray(i,il); for(int m = 0; m < 2*l+1; m++) { - d_qnarray(iatom,jj++) = d_qnm(iatom,il,m).re * qnfac; - d_qnarray(iatom,jj++) = d_qnm(iatom,il,m).im * qnfac; + d_qnarray(i,jj++) = d_qnm(ii,il,m).re * qnfac; + d_qnarray(i,jj++) = d_qnm(ii,il,m).im * qnfac; } } } diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.h b/src/KOKKOS/compute_orientorder_atom_kokkos.h index 01d9993af2..4964df52d4 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.h +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.h @@ -87,7 +87,7 @@ class ComputeOrientOrderAtomKokkos : public ComputeOrientOrderAtom { typename AT::t_float_2d d_qnarray; private: - int inum; + int inum,chunk_size,chunk_offset; typename AT::t_x_array_randomread x; typename ArrayTypes::t_int_1d mask; diff --git a/src/compute_orientorder_atom.cpp b/src/compute_orientorder_atom.cpp index 2abe4e3bb3..c759d14030 100644 --- a/src/compute_orientorder_atom.cpp +++ b/src/compute_orientorder_atom.cpp @@ -61,6 +61,7 @@ ComputeOrientOrderAtom::ComputeOrientOrderAtom(LAMMPS *lmp, int narg, char **arg wlflag = 0; wlhatflag = 0; qlcompflag = 0; + chunksize = 16384; // specify which orders to request @@ -143,6 +144,13 @@ ComputeOrientOrderAtom::ComputeOrientOrderAtom(LAMMPS *lmp, int narg, char **arg error->all(FLERR,"Illegal compute orientorder/atom command"); cutsq = cutoff*cutoff; iarg += 2; + } else if (strcmp(arg[iarg],"chunksize") == 0) { + if (iarg+2 > narg) + error->all(FLERR,"Illegal compute orientorder/atom command"); + chunksize = force->numeric(FLERR,arg[iarg+1]); + if (chunksize <= 0) + error->all(FLERR,"Illegal compute orientorder/atom command"); + iarg += 2; } else error->all(FLERR,"Illegal compute orientorder/atom command"); } diff --git a/src/compute_orientorder_atom.h b/src/compute_orientorder_atom.h index 46894db373..4e5084bfcd 100644 --- a/src/compute_orientorder_atom.h +++ b/src/compute_orientorder_atom.h @@ -62,6 +62,7 @@ class ComputeOrientOrderAtom : public Compute { virtual void init_clebsch_gordan(); double *cglist; // Clebsch-Gordan coeffs int idxcg_max; + int chunksize; }; } -- GitLab From 60bba3e238d7adbc0f5705f9db112ab34c1df4a2 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 4 Mar 2020 13:08:55 -0700 Subject: [PATCH 044/577] Fix var name --- src/KOKKOS/compute_orientorder_atom_kokkos.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp index a4a4451197..0b32d10ace 100644 --- a/src/KOKKOS/compute_orientorder_atom_kokkos.cpp +++ b/src/KOKKOS/compute_orientorder_atom_kokkos.cpp @@ -154,9 +154,9 @@ void ComputeOrientOrderAtomKokkos::compute_peratom() Kokkos::parallel_reduce("ComputeOrientOrderAtomKokkos::find_max_neighs",inum, FindMaxNumNeighs(k_list), Kokkos::Experimental::Max(maxneigh)); if (chunk_size > d_distsq.extent(0) || maxneigh > d_distsq.extent(1)) { - d_distsq = t_sna_2d_lr("orientorder/atom:distsq",nmax,maxneigh); - d_nearest = t_sna_2i_lr("orientorder/atom:nearest",nmax,maxneigh); - d_rlist = t_sna_3d_lr("orientorder/atom:rlist",nmax,maxneigh,3); + d_distsq = t_sna_2d_lr("orientorder/atom:distsq",chunk_size,maxneigh); + d_nearest = t_sna_2i_lr("orientorder/atom:nearest",chunk_size,maxneigh); + d_rlist = t_sna_3d_lr("orientorder/atom:rlist",chunk_size,maxneigh,3); d_distsq_um = d_distsq; d_rlist_um = d_rlist; -- GitLab From 437055f9130b1e083ec78d9a6cceb37503f14189 Mon Sep 17 00:00:00 2001 From: "Jibril B. Coulibaly" Date: Thu, 12 Mar 2020 11:11:38 -0500 Subject: [PATCH 045/577] implement the `scale` keyword of `fix adapt` for diameter and charge --- src/fix_adapt.cpp | 51 ++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 25 deletions(-) diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 8668690e1d..10ac290d02 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -235,7 +235,7 @@ int FixAdapt::setmask() void FixAdapt::post_constructor() { - if (!resetflag) return; + // Create local Fix Store even when ressetflag == false, to be able to use `scale` keyword for charge and diameter if (!diamflag && !chgflag) return; // new id = fix-ID + FIX_STORE_ATTRIBUTE @@ -251,7 +251,7 @@ void FixAdapt::post_constructor() newarg[4] = (char *) "1"; newarg[5] = (char *) "1"; - if (diamflag) { + if (diamflag && atom->radius_flag) {// Previously unsafe! The radius_flag was not checked, could run an atom_style w/o radius attribute and get here without a previous check / error ! int n = strlen(id) + strlen("_FIX_STORE_DIAM") + 1; id_fix_diam = new char[n]; strcpy(id_fix_diam,id); @@ -274,7 +274,7 @@ void FixAdapt::post_constructor() } } - if (chgflag) { + if (chgflag && atom->q_flag) {// Previously unsafe! The q_flag was not checked, could run an atom_style w/o charge attribute and get here without a previous check / error ! int n = strlen(id) + strlen("_FIX_STORE_CHG") + 1; id_fix_chg = new char[n]; strcpy(id_fix_chg,id); @@ -455,7 +455,7 @@ void FixAdapt::init() } // fixes that store initial per-atom values - + /* Unnecessary ? `fix_diam` and `fix_chg` seem to be already defined in FixAdapt::post_constructor(), commenting them out does not crash my MWE if (id_fix_diam) { int ifix = modify->find_fix(id_fix_diam); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); @@ -465,7 +465,7 @@ void FixAdapt::init() int ifix = modify->find_fix(id_fix_chg); if (ifix < 0) error->all(FLERR,"Could not find fix adapt storage fix ID"); fix_chg = (FixStore *) modify->fix[ifix]; - } + }*/ if (strstr(update->integrate_style,"respa")) nlevels_respa = ((Respa *) update->integrate)->nlevels; @@ -568,38 +568,39 @@ void FixAdapt::change_settings() // also scale rmass to new value if (ad->aparam == DIAMETER) { - int mflag = 0; - if (atom->rmass_flag) mflag = 1; + /* `mflag` unnecessary ? the test if (!atom->radius_flag) in FixAdapt::init() should perevent `atom->rmass_flag == false`. Unless there can be combinations of atoms with `radius` but without `rmass` + It could also be unsafe since rmass_flag could be added using `fix property/atom` even for an atom_style that does not have radius attributes */ double density; - double *radius = atom->radius; + double *vec = fix_diam->vstore; // Get initial radius to use `scale` keyword + double *radius = atom->radius; double *rmass = atom->rmass; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; - if (mflag == 0) { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) - radius[i] = 0.5*value; - } else { - for (i = 0; i < nall; i++) - if (mask[i] & groupbit) { - density = rmass[i] / (4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i]); - radius[i] = 0.5*value; - rmass[i] = 4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i] * density; - } - } + for (i = 0; i < nall; i++) + if (mask[i] & groupbit) { + density = rmass[i] / (4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i]); + if (scaleflag) radius[i] = value * vec[i]; + else radius[i] = 0.5*value; + rmass[i] = 4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i] * density; + } + } else if (ad->aparam == CHARGE) { - double *q = atom->q; + double *vec = fix_chg->vstore; // Get initial charge to use `scale` keyword + double *q = atom->q; int *mask = atom->mask; int nlocal = atom->nlocal; int nall = nlocal + atom->nghost; for (i = 0; i < nall; i++) - if (mask[i] & groupbit) q[i] = value; + if (mask[i] & groupbit) { + if (scaleflag) q[i] = value * vec[i]; + else q[i] = value; + } } } } @@ -607,7 +608,7 @@ void FixAdapt::change_settings() modify->addstep_compute(update->ntimestep + nevery); // re-initialize pair styles if any PAIR settings were changed - // ditto for bond styles if any BOND setitings were changes + // ditto for bond styles if any BOND settings were changed // this resets other coeffs that may depend on changed values, // and also offset and tail corrections -- GitLab From 14bade977e8064c9cc5b09f3701940832585d080 Mon Sep 17 00:00:00 2001 From: "Jibril B. Coulibaly" Date: Fri, 13 Mar 2020 10:59:11 -0500 Subject: [PATCH 046/577] implement diameter/disc option for 2d simulations --- src/fix_adapt.cpp | 30 ++++++++++++++++++++---------- src/fix_adapt.h | 1 + 2 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/fix_adapt.cpp b/src/fix_adapt.cpp index 10ac290d02..ee85d054c8 100644 --- a/src/fix_adapt.cpp +++ b/src/fix_adapt.cpp @@ -15,6 +15,7 @@ #include #include "atom.h" #include "bond.h" +#include "domain.h" #include "update.h" #include "group.h" #include "modify.h" @@ -139,9 +140,11 @@ nadapt(0), id_fix_diam(NULL), id_fix_chg(NULL), adapt(NULL) } else if (strcmp(arg[iarg],"atom") == 0) { if (iarg+3 > narg) error->all(FLERR,"Illegal fix adapt command"); adapt[nadapt].which = ATOM; - if (strcmp(arg[iarg+1],"diameter") == 0) { + if (strcmp(arg[iarg+1],"diameter") == 0 || strcmp(arg[iarg+1],"diameter/disc") == 0) { adapt[nadapt].aparam = DIAMETER; diamflag = 1; + discflag = 0; + if(strcmp(arg[iarg+1],"diameter/disc") == 0) discflag = 1; } else if (strcmp(arg[iarg+1],"charge") == 0) { adapt[nadapt].aparam = CHARGE; chgflag = 1; @@ -428,6 +431,8 @@ void FixAdapt::init() if (ad->aparam == DIAMETER) { if (!atom->radius_flag) error->all(FLERR,"Fix adapt requires atom attribute diameter"); + if(discflag && domain->dimension!=2) + error->all(FLERR,"Fix adapt requires 2d simulation"); } if (ad->aparam == CHARGE) { if (!atom->q_flag) @@ -568,8 +573,8 @@ void FixAdapt::change_settings() // also scale rmass to new value if (ad->aparam == DIAMETER) { - /* `mflag` unnecessary ? the test if (!atom->radius_flag) in FixAdapt::init() should perevent `atom->rmass_flag == false`. Unless there can be combinations of atoms with `radius` but without `rmass` - It could also be unsafe since rmass_flag could be added using `fix property/atom` even for an atom_style that does not have radius attributes */ + /* `mflag` unnecessary ? the test `if(!atom->radius_flag)` in `FixAdapt::init()` should perevent `atom->rmass_flag == false`. Unless there can be combinations of atom styles with `radius` but without `rmass` + It could also be unsafe since rmass_flag could be added using `fix property/atom` even for an atom_style that does not have radius attribute, although that possibility should be avoided as well with the test `if(!atom->radius_flag)` in `FixAdapt::init()` */ double density; double *vec = fix_diam->vstore; // Get initial radius to use `scale` keyword @@ -581,12 +586,14 @@ void FixAdapt::change_settings() for (i = 0; i < nall; i++) if (mask[i] & groupbit) { - density = rmass[i] / (4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i]); + if(discflag) density = rmass[i] / (MY_PI * radius[i]*radius[i]); + else density = rmass[i] / (4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i]); if (scaleflag) radius[i] = value * vec[i]; else radius[i] = 0.5*value; - rmass[i] = 4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i] * density; + if(discflag) rmass[i] = MY_PI * radius[i]*radius[i] * density; + else rmass[i] = 4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i] * density; } } else if (ad->aparam == CHARGE) { @@ -671,10 +678,13 @@ void FixAdapt::restore_settings() for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { - density = rmass[i] / (4.0*MY_PI/3.0 * - radius[i]*radius[i]*radius[i]); + if(discflag) density = rmass[i] / (MY_PI * radius[i]*radius[i]); + else density = rmass[i] / (4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i]); radius[i] = vec[i]; - rmass[i] = 4.0*MY_PI/3.0 * radius[i]*radius[i]*radius[i] * density; + if(discflag) rmass[i] = MY_PI * radius[i]*radius[i] * density; + else rmass[i] = 4.0*MY_PI/3.0 * + radius[i]*radius[i]*radius[i] * density; } } if (chgflag) { diff --git a/src/fix_adapt.h b/src/fix_adapt.h index 0bb594b7a4..dbf8f5f792 100644 --- a/src/fix_adapt.h +++ b/src/fix_adapt.h @@ -47,6 +47,7 @@ class FixAdapt : public Fix { int nlevels_respa; char *id_fix_diam,*id_fix_chg; class FixStore *fix_diam,*fix_chg; + int discflag; struct Adapt { int which,ivar; -- GitLab From 8b8f928347812d959d940f9d9e0132e187df16fc Mon Sep 17 00:00:00 2001 From: "Jibril B. Coulibaly" Date: Fri, 13 Mar 2020 12:19:16 -0500 Subject: [PATCH 047/577] update documentation --- doc/src/fix_adapt.rst | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/doc/src/fix_adapt.rst b/doc/src/fix_adapt.rst index 0e57ec98c1..e96a4ed654 100644 --- a/doc/src/fix_adapt.rst +++ b/doc/src/fix_adapt.rst @@ -15,7 +15,7 @@ Syntax * adapt = style name of this fix command * N = adapt simulation settings every this many timesteps * one or more attribute/arg pairs may be appended -* attribute = *pair* or *kspace* or *atom* +* attribute = *pair* or *bond* or *kspace* or *atom* .. parsed-literal:: @@ -90,8 +90,8 @@ the end of a simulation. Even if *reset* is specified as *yes*\ , a restart file written during a simulation will contain the modified settings. -If the *scale* keyword is set to *no*\ , then the value the parameter is -set to will be whatever the variable generates. If the *scale* +If the *scale* keyword is set to *no*\ , then the value of the altered +parameter will be whatever the variable generates. If the *scale* keyword is set to *yes*\ , then the value of the altered parameter will be the initial value of that parameter multiplied by whatever the variable generates. I.e. the variable is now a "scale factor" applied @@ -324,26 +324,23 @@ The *atom* keyword enables various atom properties to be changed. The current list of atom parameters that can be varied by this fix: * charge = charge on particle -* diameter = diameter of particle +* diameter, or, diameter/disc = diameter of particle The *v\_name* argument of the *atom* keyword is the name of an :doc:`equal-style variable ` which will be evaluated each time -this fix is invoked to set the parameter to a new value. It should be -specified as v\_name, where name is the variable name. See the +this fix is invoked to set, or scale, the parameter to a new value. +It should be specified as v\_name, where name is the variable name. See the discussion above describing the formulas associated with equal-style variables. The new value is assigned to the corresponding attribute for all atoms in the fix group. -.. note:: - - The *atom* keyword works this way whether the *scale* keyword is - set to *no* or *yes*\ . I.e. the use of scale yes is not yet supported - by the *atom* keyword. - If the atom parameter is *diameter* and per-atom density and per-atom mass are defined for particles (e.g. :doc:`atom_style granular `), then the mass of each particle is also -changed when the diameter changes (density is assumed to stay -constant). +changed when the diameter changes. The mass is set from the particle volume +for 3d systems (density is assumed to stay constant). For 2d, the default is +for LAMMPS to model particles with a radius attribute as spheres. +However, if the atom parameter is *diameter/disc*, then the mass is +set from the particle area (the density is assumed to be in mass/distance^2 units). For example, these commands would shrink the diameter of all granular particles in the "center" group from 1.0 to 0.1 in a linear fashion -- GitLab From 05b273d73176a11bfb3911cb0b00e99ad33b43e2 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:11:58 -0500 Subject: [PATCH 048/577] kim_property command A new KIM command to make it as easy as possible to write material properties computed in LAMMPS to standard KIM property instance format. --- src/KIM/kim_property.cpp | 489 +++++++++++++++++++++++++++++++++++++++ src/KIM/kim_property.h | 85 +++++++ 2 files changed, 574 insertions(+) create mode 100644 src/KIM/kim_property.cpp create mode 100644 src/KIM/kim_property.h diff --git a/src/KIM/kim_property.cpp b/src/KIM/kim_property.cpp new file mode 100644 index 0000000000..888aa4da0c --- /dev/null +++ b/src/KIM/kim_property.cpp @@ -0,0 +1,489 @@ +/* ---------------------------------------------------------------------- + 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Yaser Afshar (UMN) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, see . + + Linking LAMMPS statically or dynamically with other modules is making a + combined work based on LAMMPS. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + In addition, as a special exception, the copyright holders of LAMMPS give + you permission to combine LAMMPS with free software programs or libraries + that are released under the GNU LGPL and with code included in the standard + release of the "kim-api" under the CDDL (or modified versions of such code, + with unchanged license). You may copy and distribute such a system following + the terms of the GNU GPL for LAMMPS and the licenses of the other code + concerned, provided that you include the source code of that other code + when and as the GNU GPL requires distribution of source code. + + Note that people who make modified versions of LAMMPS are not obligated to + grant this special exception for their modified versions; it is their choice + whether to do so. The GNU General Public License gives permission to release + a modified version without this exception; this exception also makes it + possible to release a modified version which carries forward this exception. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Designed for use with the kim-api-2.1.0 (and newer) package +------------------------------------------------------------------------- */ + +#if LMP_PYTHON +#define PY_SSIZE_T_CLEAN +#include +#endif + +#include "kim_property.h" + +#include "comm.h" +#include "input.h" +#include "variable.h" +#include "utils.h" +#include "error.h" + +#include + +using namespace LAMMPS_NS; + +/* ---------------------------------------------------------------------- */ + +kimProperty::kimProperty(LAMMPS *lmp) : Pointers(lmp) +{ +#if LMP_PYTHON +#if PY_MAJOR_VERSION != 3 + error->all(FLERR, "Invalid Python version.\n" + "The kim-property Python package requires Python " + "3 >= 3.6 support."); +#endif + // one-time initialization of Python interpreter + if (!Py_IsInitialized()) { + Py_Initialize(); + PyEval_InitThreads(); + } +#else + error->all(FLERR, "Error Python support missing! Compile with PYTHON " + "package installed!"); +#endif // LMP_PYTHON +} + +void kimProperty::command(int narg, char **arg) +{ +#if LMP_PYTHON +#if PY_MAJOR_VERSION == 3 + if (narg < 2) + error->all(FLERR, "Invalid `kim_property` command."); + + if (!(strcmp(arg[0], "create") == 0) && + !(strcmp(arg[0], "destroy") == 0) && + !(strcmp(arg[0], "modify") == 0) && + !(strcmp(arg[0], "remove") == 0) && + !(strcmp(arg[0], "dump") == 0)) { + std::string msg("Error incorrect arguments in kim_property command.\n"); + msg += "`kim_property create/destroy/modify/remove/dump` "; + msg += "is mandatory."; + error->all(FLERR, msg.c_str()); + } + + if (comm->me == 0) { + std::string msg; + msg = "#=== kim-property ===========================================\n"; + input->write_echo(msg.c_str()); + } + + // Get the kim_str ptr to the data associated with a kim_property_str + // variable + char *kim_str = + input->variable->retrieve(const_cast("kim_property_str")); + + char **kim_str_cmd = new char *[3]; + kim_str_cmd[0] = const_cast("kim_property_str"); + + PyGILState_STATE gstate = PyGILState_Ensure(); + + // kim_property module + PyObject *kim_property = NULL; + + // import kim_property + { + PyObject *obj = PyUnicode_FromString("kim_property"); + if (!obj) { + PyGILState_Release(gstate); + error->all(FLERR, "Error creating a `PyObject`!"); + } + + kim_property = PyImport_Import(obj); + if (!kim_property) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to import Python `kim_property` module!" + "\nkim-property Python package can be installed " + "with pip:\n`pip install kim-property`\n" + "See the installation instructions at\n" + "https://github.com/openkim/kim-property#installing-kim-property\n") + "for detailed information."); + } + + // Decrementing of the reference count + Py_XDECREF(obj); + } + + // kim_property create 1 cohesive-potential-energy-cubic-crystal + if (strcmp(arg[0], "create") == 0) { + if (narg != 3) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property create` command."); + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + Py_ssize_t const nSize = (kim_str ? 3 : 2); + + // Python function + // This is the equivalent of the Python expression: + // kim_property.kim_property_create. + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_create"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_create` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(nSize); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + // Property ID + PyObject *pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 0, pValue); + + // Property name + pValue = PyUnicode_FromString(arg[2]); + PyTuple_SetItem(pArgs, 1, pValue); + + if (nSize == 3) { + pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 2, pValue); + } + + // call the Python kim_property_create function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_create` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + if (kim_str) { + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + } else { + kim_str_cmd[1] = const_cast("string"); + input->variable->set(3, kim_str_cmd); + } + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "destroy") == 0) { + if (narg != 2) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property destroy` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + return; + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + // Python function + // This is the equivalent of the Python expression kim_property.kim_property_destroy + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_destroy"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_destroy` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(2); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 1, pValue); + + // call the Python kim_property_destroy function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_destroy` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "modify") == 0) { + if (narg < 6) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property modify` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + error->all(FLERR, "Error There is no property instance to modify " + "the content."); + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + // Python function + // This is the equivalent of the Python expression + // kim_property.kim_property_modify + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_modify"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_modify` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(static_cast(narg)); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 1, pValue); + + for (Py_ssize_t i = 2; i < static_cast(narg); ++i) { + pValue = PyUnicode_FromString(arg[i]); + PyTuple_SetItem(pArgs, i, pValue); + } + + // call the Python kim_property_modify function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_modify` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "remove") == 0) { + if (narg < 4) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property remove` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + error->all(FLERR, "Error There is no property instance to remove " + "the content."); + } + + int const ID = utils::inumeric(FLERR, arg[1], true, lmp); + + // Python function + // This is the equivalent of the Python expression + // kim_property.kim_property_remove + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_remove"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_remove` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(static_cast(narg)); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Error could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyLong_FromLong(ID); + PyTuple_SetItem(pArgs, 1, pValue); + + for (Py_ssize_t i = 2; i < static_cast(narg); ++i) { + pValue = PyUnicode_FromString(arg[i]); + PyTuple_SetItem(pArgs, i, pValue); + } + + // call the Python kim_property_remove function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_remove` function " + "evaluation failed!"); + } + + // Python function returned a string value + const char *pystr = PyUnicode_AsUTF8(pValue); + + kim_str_cmd[2] = const_cast(pystr); + + input->variable->set_string(kim_str_cmd[0], kim_str_cmd[2]); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + else if (strcmp(arg[0], "dump") == 0) { + if (narg != 2) { + PyGILState_Release(gstate); + error->all(FLERR, "Error invalid `kim_property dump` command."); + } + + if (!kim_str) { + PyGILState_Release(gstate); + error->all(FLERR, "Error There is no property instance to dump " + "the content."); + } + + // Python function + // This is the equivalent of the Python expression + // kim_property.kim_property_dump + PyObject *pFunc = + PyObject_GetAttrString(kim_property, "kim_property_dump"); + if (!pFunc) { + PyGILState_Release(gstate); + error->all(FLERR, "Error unable to get an attribute named " + "`kim_property_dump` from a kim_property object!"); + } + + // Decrementing of the reference count + Py_XDECREF(kim_property); + + // create Python tuple of input arguments + PyObject *pArgs = PyTuple_New(2); + if (!pArgs) { + PyGILState_Release(gstate); + error->all(FLERR, "Could not create Python function arguments."); + } + + // Python object to set the tuple + PyObject *pValue = PyUnicode_FromString(kim_str); + PyTuple_SetItem(pArgs, 0, pValue); + + pValue = PyUnicode_FromString(arg[1]); + PyTuple_SetItem(pArgs, 1, pValue); + + if (comm->me == 0) { + // call the Python kim_property_dump function + // error check with one() since only some procs may fail + pValue = PyObject_CallObject(pFunc, pArgs); + if (!pValue) { + PyErr_Print(); + PyGILState_Release(gstate); + error->one(FLERR, "Error Python `kim_property_dump` function " + "evaluation failed!"); + } + } + + // Destroy the variable + kim_str_cmd[1] = const_cast("delete"); + input->variable->set(2, kim_str_cmd); + + Py_XDECREF(pArgs); + Py_XDECREF(pFunc); + Py_XDECREF(pValue); + } + + PyGILState_Release(gstate); + + delete[] kim_str_cmd; +#endif // PY_MAJOR_VERSION +#endif // LMP_PYTHON +} diff --git a/src/KIM/kim_property.h b/src/KIM/kim_property.h new file mode 100644 index 0000000000..ff5faa6781 --- /dev/null +++ b/src/KIM/kim_property.h @@ -0,0 +1,85 @@ +/* -*- 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. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Contributing author: Yaser Afshar (UMN) +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along with + this program; if not, see . + + Linking LAMMPS statically or dynamically with other modules is making a + combined work based on LAMMPS. Thus, the terms and conditions of the GNU + General Public License cover the whole combination. + + In addition, as a special exception, the copyright holders of LAMMPS give + you permission to combine LAMMPS with free software programs or libraries + that are released under the GNU LGPL and with code included in the standard + release of the "kim-api" under the CDDL (or modified versions of such code, + with unchanged license). You may copy and distribute such a system following + the terms of the GNU GPL for LAMMPS and the licenses of the other code + concerned, provided that you include the source code of that other code + when and as the GNU GPL requires distribution of source code. + + Note that people who make modified versions of LAMMPS are not obligated to + grant this special exception for their modified versions; it is their choice + whether to do so. The GNU General Public License gives permission to release + a modified version without this exception; this exception also makes it + possible to release a modified version which carries forward this exception. +------------------------------------------------------------------------- */ + +/* ---------------------------------------------------------------------- + Designed for use with the kim-api-2.1.0 (and newer) package +------------------------------------------------------------------------- */ + +#ifdef COMMAND_CLASS + +CommandStyle(kim_property, kimProperty) + +#else + +#ifndef LMP_KIM_PROPERTY_H +#define LMP_KIM_PROPERTY_H + +#include "pointers.h" + +namespace LAMMPS_NS +{ + +class kimProperty : protected Pointers +{ +public: + kimProperty(class LAMMPS *lmp); + + void command(int, char **); +}; + +} // namespace LAMMPS_NS + +#endif // LMP_KIM_PROPERTY_H +#endif // COMMAND_CLASS + +/* ERROR/WARNING messages: + +*/ -- GitLab From dc373dbdeb23b2dd1fd23cd3900dd034915da008 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:15:59 -0500 Subject: [PATCH 049/577] updating the kim_commands doc --- doc/src/kim_commands.rst | 550 +++++++++++++++++++++++++++++++++++---- 1 file changed, 503 insertions(+), 47 deletions(-) diff --git a/doc/src/kim_commands.rst b/doc/src/kim_commands.rst index c710ddfe5d..aca2529ec7 100644 --- a/doc/src/kim_commands.rst +++ b/doc/src/kim_commands.rst @@ -1,16 +1,19 @@ -.. index:: kim_init, kim_interactions, kim_query, kim_param +.. index:: kim_init, kim_interactions, kim_query, kim_param, kim_property -kim_init command -================= +:ref:`kim_init` command +========================================= -kim_interactions command -========================= +:ref:`kim_interactions` command +========================================================= -kim_query command -================== +:ref:`kim_query` command +=========================================== -kim_param command -================== +:ref:`kim_param` command +=========================================== + +:ref:`kim_property` command +================================================= Syntax """""" @@ -22,6 +25,11 @@ Syntax kim_query variable formatarg query_function queryargs kim_param get param_name index_range variables formatarg kim_param set param_name index_range values + kim_property create instance_id property_id + kim_property modify instance_id key key_name key_name_key key_name_value + kim_property remove instance_id key key_name + kim_property destroy instance_id + kim_property dump file .. _formatarg_options: @@ -41,13 +49,19 @@ Syntax on the prefix specified in *variable* and a number appended to indicate which element in the list of values is in the variable. *explicit* = returns the values separately in one more more variable names - provided as arguments that precede *formatarg*\ . [default for *kim_param*] + provided as arguments that preceed *formatarg*\ . [default for *kim_param*] * query_function = name of the OpenKIM web API query function to be used * queryargs = a series of *keyword=value* pairs that represent the web query; supported keywords depend on the query function * param_name = name of a KIM portable model parameter * index_range = KIM portable model parameter index range (an integer for a single element, or pair of integers separated by a colon for a range of elements) * values = new value(s) to replace the current value(s) of a KIM portable model parameter +* instance_id = a positive integer identifying the KIM property instance +* property_id = identifier of a `KIM Property Definition `_, which can be (1) a property short name, (2) the full unique ID of the property (including the contributor and date), (3) a file name corresponding to a local property definition file +* key_name = one of the keys belonging to the specified KIM property definition +* key_name_key = a key belonging to a key-value pair (standardized in the `KIM Properties Framework `__) +* key_name_value = value to be associated with a key_name_key in a key-value pair +* file = name of a file to write the currently defined set of KIM property instances to Examples """""""" @@ -64,6 +78,15 @@ Examples kim_query a0 get_lattice_constant_cubic crystal=["fcc"] species=["Al"] units=["angstrom"] kim_param get gamma 1 varGamma kim_param set gamma 1 3.0 + kim_property create 1 atomic-mass + kim_property modify 1 key mass source-value 26.98154 + kim_property modify 1 key species source-value Al + kim_property remove 1 key species + kim_property destroy 1 + kim_property dump results.edn + + +.. _kim_description: Description """"""""""" @@ -157,11 +180,10 @@ See the `current list of KIM PMs and SMs archived in OpenKIM `_ to -learn how to install a pre-build binary of the OpenKIM Repository of Models. +See `Obtaining KIM Models `_ to +learn how to install a pre-built binary of the OpenKIM Repository of Models. .. note:: - It is also possible to locally install IMs not archived in OpenKIM, in which case their names do not have to conform to the KIM ID format. @@ -169,15 +191,17 @@ Using OpenKIM IMs with LAMMPS ----------------------------- Two commands are employed when using OpenKIM IMs, one to select the -IM and perform necessary initialization (*kim_init*), and the second +IM and perform necessary initialization (\ *kim_init*\ ), and the second to set up the IM for use by executing any necessary LAMMPS commands -(*kim_interactions*). Both are required. +(\ *kim_interactions*\ ). Both are required. See the *examples/kim* directory for example input scripts that use KIM PMs and KIM SMs. +.. _kim_init command: + OpenKIM IM Initialization (*kim_init*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The *kim_init* mode command must be issued **before** the simulation box is created (normally at the top of the file). @@ -219,7 +243,7 @@ either match the required units of the IM or the IM must be able to adjust its units to match. (The latter is only possible with some KIM PMs; SMs can never adjust their units.) If a match is possible, the LAMMPS :doc:`units ` command is called to set the units to -*user_units*. If the match fails, the simulation is terminated with +*user_units*\ . If the match fails, the simulation is terminated with an error. Here is an example of a LAMMPS script to compute the cohesive energy @@ -324,8 +348,10 @@ be done to convert the box and all atomic positions to the correct units: all appropriate places in the input script. It is up to the user to do this correctly. +.. _kim_interactions command: + OpenKIM IM Execution (*kim_interactions*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The second and final step in using an OpenKIM IM is to execute the *kim_interactions* command. This command must be preceded by a *kim_init* @@ -399,12 +425,17 @@ the *kim_interactions* command executes the following LAMMPS input commands: pair_coeff * * ffield.reax.rdx C H N O fix reaxqeq all qeq/reax 1 0.0 10.0 1.0e-6 param.qeq -Note that the files *lmp_control*, *ffield.reax.rdx* and *param.qeq* -are specific to the Strachan et al. (2003) ReaxFF parameterization -and are archived as part of the SM package in OpenKIM. -Note also that parameters like cutoff radii and charge tolerances, -which have an effect on IM predictions, are also included in the -SM definition ensuring reproducibility. +.. note:: + + The files *lmp_control*, *ffield.reax.rdx* and *param.qeq* + are specific to the Strachan et al. (2003) ReaxFF parameterization + and are archived as part of the SM package in OpenKIM. + +.. note:: + + Parameters like cutoff radii and charge tolerances, + which have an effect on IM predictions, are also included in the + SM definition ensuring reproducibility. .. note:: @@ -414,8 +445,10 @@ SM definition ensuring reproducibility. bond_coeff, fixes related to charge equilibration, etc.) should normally not appear in the input script. +.. _kim_query command: + Using OpenKIM Web Queries in LAMMPS (*kim_query*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The *kim_query* command performs a web query to retrieve the predictions of an IM set by *kim_init* for material properties archived in @@ -427,6 +460,7 @@ of an IM set by *kim_init* for material properties archived in The syntax for the *kim_query* command is as follows: + .. code-block:: LAMMPS kim_query variable formatarg query_function queryargs @@ -442,7 +476,7 @@ individual variables of the form *prefix_I*, where *prefix* is set to the *kim_query* *variable* argument and *I* ranges from 1 to the number of returned values. The number and order of the returned values is determined by the type of query performed. (Note that the "explicit" setting of -*formatarg* is not supported by *kim_query*.) +*formatarg* is not supported by *kim_query*\ .) .. note:: @@ -452,7 +486,7 @@ by the type of query performed. (Note that the "explicit" setting of cases will generate an error. The second required argument *query_function* is the name of the -query function to be called (e.g. *get_lattice_constant_cubic*). +query function to be called (e.g. *get_lattice_constant_cubic*\ ). All following :doc:`arguments ` are parameters handed over to the web query in the format *keyword=value*\ , where *value* is always an array of one or more comma-separated items in brackets. @@ -466,7 +500,7 @@ is available on the OpenKIM webpage at All query functions require the *model* keyword, which identifies the IM whose predictions are being queried. This keyword is automatically generated by *kim_query* based on the IM set in *kim_init* and must not - be specified as an argument to *kim_query*. + be specified as an argument to *kim_query*\ . .. note:: @@ -475,11 +509,11 @@ is available on the OpenKIM webpage at used to compute this property. In cases where there are multiple methods in OpenKIM for computing a property, a *method* keyword can be provided to select the method of choice. See the - `query documentation `_ - to see which methods are available for a given *query function*\ . + `query documentation `_ + to see which methods are available for a given *query_function*\ . *kim_query* Usage Examples and Further Clarifications -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ The data obtained by *kim_query* commands can be used as part of the setup or analysis phases of LAMMPS simulations. Some examples are given below. @@ -502,10 +536,12 @@ crystal. By using *kim_query*, the user is saved the trouble and possible error of tracking this value down, or of having to perform an energy minimization to find the equilibrium lattice constant. -Note that in *unit_conversion_mode* the results obtained from a -*kim_query* would need to be converted to the appropriate units system. -For example, in the above script, the lattice command would need to be -changed to: "lattice fcc ${a0}\*${_u_distance}". +.. note:: + + In *unit_conversion_mode* the results obtained from a + *kim_query* would need to be converted to the appropriate units system. + For example, in the above script, the lattice command would need to be + changed to: "lattice fcc ${a0}*${_u_distance}". **Define an equilibrium hcp crystal** @@ -524,7 +560,7 @@ changed to: "lattice fcc ${a0}\*${_u_distance}". In this case the *kim_query* returns two arguments (since the hexagonal close packed (hcp) structure has two independent lattice constants). The *formatarg* keyword "split" places the two values into -the variables *latconst_1* and *latconst_2*. (These variables are +the variables *latconst_1* and *latconst_2*\ . (These variables are created if they do not already exist.) For convenience the variables *a0* and *c0* are created in order to make the remainder of the input script more readable. @@ -555,9 +591,9 @@ potential. If no tolerance is passed a default value is used. If multiple results are returned (indicating that the tolerance is too large), *kim_query* will return an error. See the - `query documentation `_ + `query documentation `_ to see which numerical arguments and tolerances are available for a - given *query function*\ . + given *query_function*\ . **Compute defect formation energy** @@ -586,8 +622,10 @@ ideal fcc cohesive energy of the atoms in the system obtained from from these programs are queried is tracked. No other information about the nature of the query or its source is recorded. +.. _kim_param command: + Accessing KIM Model Parameters from LAMMPS (*kim_param*) -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ All IMs are functional forms containing a set of parameters. The values of these parameters are typically @@ -620,7 +658,7 @@ for details). .. note:: - The *kim_param get/set* commands must be preceded by *kim_init*. + The *kim_param get/set* commands must be preceded by *kim_init*\ . The *kim_param set* command must additionally be preceded by a *kim_interactions* command (or alternatively by a *pair_style kim* and *pair_coeff* commands). The *kim_param set* command may be used wherever a *pair_coeff* command may occur. @@ -674,13 +712,13 @@ Multiple parameters can be retrieved with a single call to *kim_param get* by repeating the argument list following *get*\ . For a *set* operation, the *values* argument contains the new value(s) -for the element(s) of the parameter specified by *index_range*. For the case +for the element(s) of the parameter specified by *index_range*\ . For the case where multiple values are being set, *values* contains a set of values separated by spaces. Multiple parameters can be set with a single call to *kim_param set* by repeating the argument list following *set*\ . *kim_param* Usage Examples and Further Clarifications -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Examples of getting and setting KIM PM parameters with further clarifications are provided below. @@ -722,7 +760,7 @@ determined by the *formatarg* argument. In this case, *formatarg* is not specified and therefore the default "explicit" mode is used. (The behavior would be the same if the word -*explicit* were added after *LAM_TeSe*.) Elements 7, 8 and 9 of parameter +*explicit* were added after *LAM_TeSe*\ .) Elements 7, 8 and 9 of parameter lambda retrieved by the *get* operation are placed in the LAMMPS variables *LAM_TeTe*, *LAM_TeZn* and *LAM_TeSe*, respectively. @@ -765,7 +803,7 @@ contains the current value of lambda. In this case, the "split" mode of *formatarg* is used. The three values retrieved by the *get* operation are stored in -the three LAMMPS variables *LAM_15*, *LAM_16* and *LAM_17*. +the three LAMMPS variables *LAM_15*, *LAM_16* and *LAM_17*\ . The provided name "LAM" is used as prefix and the location in the lambda array is appended to create the variable names. @@ -797,7 +835,7 @@ potential, while *NEW_GAMMA* will contain the value 2.6. **Setting multiple scalar parameters with a single call** -.. parsed-literal:: +.. code-block:: LAMMPS kim_init SW_ZhouWardMartin_2013_CdTeZnSeHgS__MO_503261197030_002 metal ... @@ -824,6 +862,421 @@ In this case, elements 2 through 6 of the parameter *sigma* are set to the values 2.35214, 2.23869, 2.04516, 2.43269 and 1.80415 in order. +.. _kim_property command: + +Writing material properties computed in LAMMPS to standard KIM property instance format (*kim_property*) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +As explained :ref:`above`, +The OpenKIM system includes a collection of Tests (material property calculation codes), +Models (interatomic potentials), Predictions, and Reference Data (DFT or experiments). +Specifically, a KIM Test is a computation that when coupled with a KIM Model generates +the prediction of that model for a specific material property rigorously defined +by a KIM Property Definition (see the +`KIM Properties Framework `__ +for further details). A prediction of a material property for a given model is a specific +numerical realization of a property definition, referred to as a "Property +Instance." The objective of the *kim_property* command is to make it easy to +output material properties in a standardized, machine readable, format that can be easily +ingested by other programs. +Additionally, it aims to make it as easy as possible to convert a LAMMPS script that computes a +material property into a KIM Test that can then be uploaded to `openkim.org `_ + +A developer interested in creating a KIM Test using a LAMMPS script should +first determine whether a property definition that applies to their calculation +already exists in OpenKIM by searching the `properties page +`_. If none exists, it is possible to use a +locally defined property definition contained in a file until it can be +uploaded to the official repository (see below). Once one or more applicable +property definitions have been identified, the *kim_property create*, +*kim_property modify*, *kim_property remove*, and *kim_property destroy*, +commands provide an interface to create, set, modify, remove, and destroy +instances of them within a LAMMPS script. Their general syntax is as follows: + +.. code-block:: LAMMPS + + kim_property create instance_id property_id + kim_property modify instance_id key key_name key_name_key key_name_value + kim_property remove instance_id key key_name + kim_property destroy instance_id + kim_property dump file + +Here, *instance_id* is a positive integer used to uniquely identify each +property instance; (note that the results file can contain multiple property +instances). A property_id is an identifier of a +`KIM Property Definition `_, +which can be (1) a property short name, (2) the full unique ID of the property +(including the contributor and date), (3) a file name corresponding to a local +property definition file. Examples of each of these cases are shown below: + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property create 2 cohesive-energy-relation-cubic-crystal + +.. code-block:: LAMMPS + + kim_property create 1 tag:brunnels@noreply.openkim.org,2016-05-11:property/atomic-mass + kim_property create 2 tag:staff@noreply.openkim.org,2014-04-15:property/cohesive-energy-relation-cubic-crystal + +.. code-block:: LAMMPS + + kim_property create 1 new-property.edn + kim_property create 2 /home/mary/marys-kim-properties/dissociation-energy.edn + +In the last example, "new-property.edn" and "/home/mary/marys-kim-properties/dissociation-energy.edn" are the +names of files that contain user-defined (local) property definitions. + +A KIM property instance takes the form of a "map," i.e. a set of key-value +pairs akin to Perl's hash, Python's dictionary, or Java's Hashtable. It +consists of a set of property key names, each of which is referred to here by +the *key_name* argument, that are defined as part of the relevant KIM Property +Definition and include only lowercase alphanumeric characters and dashes. The +value paired with each property key is itself a map whose possible keys are +defined as part of the `KIM Properties Framework +`__; these keys are +referred to by the *key_name_key* argument and their associated values by the +*key_name_value* argument. These values may either be scalars or arrays, +as stipulated in the property definition. + +.. note:: + + Each map assigned to a *key_name* must contain the *key_name_key* + "source-value" and an associated *key_name_value* of the appropriate + type (as defined in the relevant KIM Property Definition). For keys that are + defined as having physical units, the + "source-unit" *key_name_key* must also be given a string value recognized + by `GNU units `_. + +Once a *kim_property create* command has been given to instantiate a property +instance, maps associated with the property's keys can be edited using the +*kim_property modify* command. In using this command, the special keyword +"key" should be given, followed by the property key name and the key-value pair +in the map associated with the key that is to be set. For example, the +`atomic-mass `_ +property definition consists of two property keys named "mass" and "species." +An instance of this property could be created like so: + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property modify 1 key species source-value Al + kim_property modify 1 key mass source-value 26.98154 + kim_property modify 1 key mass source-unit amu + +or, equivalently, + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property modify 1 key species source-value Al & + key mass source-value 26.98154 & + source-unit amu + +*kim_property* Usage Examples and Further Clarifications +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +**Create** + +.. code-block:: LAMMPS + + kim_property create instance_id property_id + +The *kim_property create* command takes as input a property instance ID and the +property definition name, and creates an initial empty property instance data +structure. For example, + +.. code-block:: LAMMPS + + kim_property create 1 atomic-mass + kim_property create 2 cohesive-energy-relation-cubic-crystal + +creates an empty property instance of the "atomic-mass" property definition +with instance ID 1 and an empty instance of the +"cohesive-energy-relation-cubic-crystal" property with ID 2. A list of +published property definitions in OpenKIM can be found on the `properties page +`_. + +One can also provide the name of a file in the current working directory or the +path of a file containing a valid property definition. For example, + +.. code-block:: LAMMPS + + kim_property create 1 new-property.edn + +where "new-property.edn" refers to a file name containing a new property +definition that does not exist in OpenKIM. + +If the *property_id* given cannot be found in OpenKIM and no file of this name +containing a valid property definition can be found, this command will produce +an error with an appropriate message. Calling *kim_property create* with the +same instance ID multiple times will also produce an error. + +**Modify** + +.. code-block:: LAMMPS + + kim_property modify instance_id key key_name key_name_key key_name_value + +The *kim_property modify* command incrementally builds the property instance +by receiving property definition keys along with associated arguments. Each +*key_name* is associated with a map containing one or more key-value pairs (in +the form of *key_name_key*-*key_name_value* pairs). For example, + +.. code-block:: LAMMPS + + kim_property modify 1 key species source-value Al + kim_property modify 1 key mass source-value 26.98154 + kim_property modify 1 key mass source-unit amu + +where the special keyword "key" is followed by a *key_name* ("species" or +"mass" in the above) and one or more key-value pairs. These key-value pairs +may continue until either another "key" keyword is given or the end of the +command line is reached. Thus, the above could equivalently be written as + +.. code-block:: LAMMPS + + kim_property modify 1 key species source-value Al & + key mass source-value 26.98154 & + key mass source-unit amu + +As an example of modifying multiple key-value pairs belonging to the map of a +single property key, the following command modifies the map of the +"cohesive-potential-energy" property key to contain the key "source-unit" which +is assigned a value of "eV" and the key "digits" which is assigned a value of +5: + +.. code-block:: LAMMPS + + kim_property modify 2 key cohesive-potential-energy source-unit eV digits 5 + +.. note:: + + The relevant data types of the values in the map are handled + automatically based on the specification of the key in the + KIM Property Definition. In the example above, + this means that the value "eV" will automatically be interpreted as a string + while the value 5 will be interpreted as an integer. + +The values contained in maps can either be scalars, as in all of the examples +above, or arrays depending on which is stipulated in the corresponding Property +Definition. For one-dimensional arrays, a single one-based index must be +supplied that indicates which element of the array is to be modified. For +multidimensional arrays, multiple indices must be given depending on the +dimensionality of the array. + +.. note:: + + All array indexing used by *kim_property modify* is one-based, i.e. the + indices are enumerated 1, 2, 3, ... + +.. note:: + + The dimensionality of arrays are defined in the the corresponding Property + Definition. The extent of each dimension of an array can either be a + specific finite number or indefinite and determined at run time. If + an array has a fixed extent, attempting to modify an out-of-range index will + fail with an error message. + +For example, the "species" property key of the +`cohesive-energy-relation-cubic-crystal +`_ +property is a one-dimensional array that can contain any number of entries +based on the number of atoms in the unit cell of a given cubic crystal. To +assign an array containing the string "Al" four times to the "source-value" key +of the "species" property key, we can do so by issuing: + +.. code-block:: LAMMPS + + kim_property modify 2 key species source-value 1 Al + kim_property modify 2 key species source-value 2 Al + kim_property modify 2 key species source-value 3 Al + kim_property modify 2 key species source-value 4 Al + +.. note:: + + No declaration of the number of elements in this array was given; + *kim_property modify* will automatically handle memory management to allow + an arbitrary number of elements to be added to the array. + +.. note:: + + In the event that *kim_property modify* is used to set the value of an + array index without having set the values of all lesser indices, they will + be assigned default values based on the data type associated with the key in + the map: + + .. table_from_list:: + :columns: 2 + + * Data type + * Default value + * int + * 0 + * float + * 0.0 + * string + * \"\" + * file + * \"\" + + For example, doing the following: + + .. code-block:: LAMMPS + + kim_property create 2 cohesive-energy-relation-cubic-crystal + kim_property modify 2 key species source-value 4 Al + + will result in the "source-value" key in the map for the property key + "species" being assigned the array ["", "", "", "Al"]. + +For convenience, the index argument provided may refer to an inclusive range of +indices by specifying two integers separated by a colon (the first integer must +be less than or equal to the second integer, and no whitespace should be +included). Thus, the snippet above could equivalently be written: + +.. code-block:: LAMMPS + + kim_property modify 2 key species source-value 1:4 Al Al Al Al + +Calling this command with a non-positive index, e.g. +``kim_property modify 2 key species source-value 0 Al``, or an incorrect +number of input arguments, e.g. +``kim_property modify 2 key species source-value 1:4 Al Al``, will result in an +error. + +As an example of modifying multidimensional arrays, consider the "basis-atoms" +key in the `cohesive-energy-relation-cubic-crystal +`_ +property definition. This is a two-dimensional array containing the fractional +coordinates of atoms in the unit cell of the cubic crystal. In the case of, +e.g. a conventional fcc unit cell, the "source-value" key in the map associated +with this key should be assigned the following value: + +.. code-block:: LAMMPS + + [[0.0, 0.0, 0.0], + [0.5, 0.5, 0.0], + [0.5, 0.0, 0.5], + [0.0, 0.5, 0.5]] + +While each of the twelve components could be set individually, we can instead set +each row at a time using colon notation: + +.. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates source-value 1 1:3 0.0 0.0 0.0 + kim_property modify 2 key basis-atom-coordinates source-value 2 1:3 0.5 0.5 0.0 + kim_property modify 2 key basis-atom-coordinates source-value 3 1:3 0.5 0.0 0.5 + kim_property modify 2 key basis-atom-coordinates source-value 4 1:3 0.0 0.5 0.5 + +Where the first index given refers to a row and the second index refers to a +column. We could, instead, choose to set each column at a time like so: + +.. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates source-value 1:4 1 0.0 0.5 0.5 0.0 & + key basis-atom-coordinates source-value 1:4 2 0.0 0.5 0.0 0.5 & + key basis-atom-coordinates source-value 1:4 3 0.0 0.0 0.5 0.5 + +.. note:: + + Multiple calls of *kim_property modify* made for the same instance ID + can be combined into a single invocation, meaning the following are + both valid: + + .. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates source-value 1 1:3 0.0 0.0 0.0 & + key basis-atom-coordinates source-value 2 1:3 0.5 0.5 0.0 & + key basis-atom-coordinates source-value 3 1:3 0.5 0.0 0.5 & + key basis-atom-coordinates source-value 4 1:3 0.0 0.5 0.5 + + .. code-block:: LAMMPS + + kim_property modify 2 key short-name source-value 1 fcc & + key species source-value 1:4 Al Al Al Al & + key a source-value 1:5 3.9149 4.0000 4.032 4.0817 4.1602 & + source-unit angstrom & + digits 5 & + key basis-atom-coordinates source-value 1 1:3 0.0 0.0 0.0 & + key basis-atom-coordinates source-value 2 1:3 0.5 0.5 0.0 & + key basis-atom-coordinates source-value 3 1:3 0.5 0.0 0.5 & + key basis-atom-coordinates source-value 4 1:3 0.0 0.5 0.5 + +.. note:: + + For multidimensional arrays, only one colon-separated range is allowed + in the index listing. Therefore, + + .. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates 1 1:3 0.0 0.0 0.0 + + is valid but + + .. code-block:: LAMMPS + + kim_property modify 2 key basis-atom-coordinates 1:2 1:3 0.0 0.0 0.0 0.0 0.0 0.0 + + is not. + +.. note:: + + After one sets a value in a map with the *kim_property modify* command, + additional calls will overwrite the previous value. + +**Remove** + +.. code-block:: LAMMPS + + kim_property remove instance_id key key_name + +The *kim_property remove* command can be used to remove a property key from a +property instance. For example, + +.. code-block:: LAMMPS + + kim_property remove 2 key basis-atom-coordinates + +**Destroy** + +.. code-block:: LAMMPS + + kim_property destroy instance_id + +The *kim_property destroy* command deletes a previously created property +instance ID. For example, + +.. code-block:: LAMMPS + + kim_property destroy 2 + +.. note:: + + If this command is called with an instance ID that does not exist, no + error is raised. + +**Dump** + +The *kim_property dump* command can be used to write the content of all +currently defined property instances to a file: + +.. code-block:: LAMMPS + + kim_property dump file + +For example, + +.. code-block:: LAMMPS + + kim_property dump results.edn + +.. note:: + + Issuing the *kim_property dump* command clears all existing property + instances from memory. + Citation of OpenKIM IMs ----------------------- @@ -847,8 +1300,11 @@ LAMMPS is built with that package. A requirement for the KIM package, is the KIM API library that must be downloaded from the `OpenKIM website `_ and installed before LAMMPS is compiled. When installing LAMMPS from binary, the kim-api package -is a dependency that is automatically downloaded and installed. See the KIM -section of the :doc:`Packages details ` for details. +is a dependency that is automatically downloaded and installed. The *kim_query* +command requires the *libcurl* library to be installed. The *kim_property* +command requires *Python* 3.6 or later and the *kim-property* python package to +be installed. See the KIM section of the :doc:`Packages details ` +for details. Furthermore, when using *kim_commands* to run KIM SMs, any packages required by the native potential being used or other commands or fixes that it invokes -- GitLab From f203258ad59c6d6462e11c3907d17d398dd339df Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:17:27 -0500 Subject: [PATCH 050/577] updating the Build_extras, KIM package --- doc/src/Build_extras.rst | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/doc/src/Build_extras.rst b/doc/src/Build_extras.rst index 4589015e35..45c876d84a 100644 --- a/doc/src/Build_extras.rst +++ b/doc/src/Build_extras.rst @@ -189,13 +189,27 @@ KIM package --------------------- To build with this package, the KIM library with API v2 must be downloaded -and built on your system. It must include the KIM models that you want to -use with LAMMPS. If you want to use the :doc:`kim_query ` +and built on your system. It must include the KIM models that you want to +use with LAMMPS. + +If you would like to use the :doc:`kim_query ` command, you also need to have libcurl installed with the matching development headers and the curl-config tool. -See the `Obtaining KIM Models `_ -web page to +If you would like to use the :doc:`kim_property ` +command, you need to build LAMMPS with the Python 3.6 or later package +installed. See the :doc:`Python ` doc page for more info on building +LAMMPS with the version of Python on your system. +After successfully building LAMMPS with Python, you need to +install the kim-property Python package, which can be easily done using +*pip* as ``pip install kim-property``, or from the *conda-forge* channel as +``conda install kim-property`` if LAMMPS is built in Conda. More detailed +information is available at: +`kim-property installation `_. + +In addition to installing the KIM API, it is also necessary to install the +library of KIM models (interatomic potentials). +See `Obtaining KIM Models `_ to learn how to install a pre-build binary of the OpenKIM Repository of Models. See the list of all KIM models here: https://openkim.org/browse/models -- GitLab From cfc9fe7e39a451109b4f32a47fd1d11dd082e0ae Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:18:19 -0500 Subject: [PATCH 051/577] updating the Commands_all, adding kim_property command --- doc/src/Commands_all.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/src/Commands_all.rst b/doc/src/Commands_all.rst index 36ae112527..92c0ba107a 100644 --- a/doc/src/Commands_all.rst +++ b/doc/src/Commands_all.rst @@ -70,6 +70,7 @@ An alphabetic list of all general LAMMPS commands. * :doc:`kim_init ` * :doc:`kim_interactions ` * :doc:`kim_param ` + * :doc:`kim_property ` * :doc:`kim_query ` * :doc:`kspace_modify ` * :doc:`kspace_style ` -- GitLab From 2d3423a49309830e6969f5870248e4bc01f3e0e9 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:19:13 -0500 Subject: [PATCH 052/577] updating the Packages_details, KIM package --- doc/src/Packages_details.rst | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/doc/src/Packages_details.rst b/doc/src/Packages_details.rst index e20c2886ed..8251c5301e 100644 --- a/doc/src/Packages_details.rst +++ b/doc/src/Packages_details.rst @@ -365,12 +365,17 @@ KIM package This package contains a set of commands that serve as a wrapper on the `Open Knowledgebase of Interatomic Models (OpenKIM) `_ -repository of interatomic models (IMs) -enabling compatible ones to be used in LAMMPS simulations. -This includes :doc:`kim_init and kim_interactions ` -commands to select, initialize and instantiate the IM, and a -:doc:`kim_query ` command to perform web queries -for material property predictions of OpenKIM IMs. +repository of interatomic models (IMs) enabling compatible ones to be used in +LAMMPS simulations. + +This includes :doc:`kim_init `, and +:doc:`kim_interactions ` commands to select, initialize and +instantiate the IM, a :doc:`kim_query ` command to perform web +queries for material property predictions of OpenKIM IMs, a +:doc:`kim_param ` command to access KIM Model Parameters from +LAMMPS, and a :doc:`kim_property ` command to write material +properties computed in LAMMPS to standard KIM property instance format. + Support for KIM IMs that conform to the `KIM Application Programming Interface (API) `_ is provided by the :doc:`pair_style kim ` command. @@ -392,13 +397,16 @@ The KIM project is led by Ellad Tadmor and Ryan Elliott (U Minnesota) and is funded by the `National Science Foundation `_. **Authors:** Ryan Elliott (U Minnesota) is the main developer for the KIM -API and the *pair_style kim* command. Axel Kohlmeyer (Temple U) and -Ellad Tadmor (U Minnesota) contributed to the :doc:`kim_commands ` -interface in close collaboration with Ryan Elliott. +API and the *pair_style kim* command. Yaser Afshar (U Minnesota), +Axel Kohlmeyer (Temple U), Ellad Tadmor (U Minnesota), and +Daniel Karls (U Minnesota) contributed to the +:doc:`kim_commands ` interface in close collaboration with +Ryan Elliott. **Install:** -This package has :ref:`specific installation instructions ` on the :doc:`Build extras ` doc page. +This package has :ref:`specific installation instructions ` on the +:doc:`Build extras ` doc page. **Supporting info:** -- GitLab From 3da1e127bf82049d220ae2f6cfe21f9837b3977e Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Mon, 16 Mar 2020 08:42:11 -0500 Subject: [PATCH 053/577] updating the false_positives with names causing warning --- doc/utils/sphinx-config/false_positives.txt | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/doc/utils/sphinx-config/false_positives.txt b/doc/utils/sphinx-config/false_positives.txt index 264c3fab50..4110682e6c 100644 --- a/doc/utils/sphinx-config/false_positives.txt +++ b/doc/utils/sphinx-config/false_positives.txt @@ -714,6 +714,7 @@ edgeIDs edihed edim edip +edn edpd eDPD edu @@ -1087,6 +1088,7 @@ Harting Hartree Hartrees Hasan +Hashtable Haswell Haugk Hayoun @@ -1344,6 +1346,7 @@ Kai Kalia Kamberaj Kapfer +Karls Karlsruhe Karniadakis Karplus @@ -1630,6 +1633,8 @@ Marroquin Marsaglia Marseille Martyna +mary +marys Masaglia Mashayak Massimilliano @@ -3135,6 +3140,7 @@ Westview wget Whelan whitesmoke +whitespace Wi Wicaksono Wijk @@ -3201,6 +3207,7 @@ xzhou yaff YAFF Yamada +Yaser Yazdani Ybar ybox -- GitLab From f1e03aefc6503423993ddcd329df6944ccbb7c64 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Tue, 17 Mar 2020 16:07:22 -0500 Subject: [PATCH 054/577] updating the pair potential docs, adding reference to OpenKIM --- doc/src/pair_adp.rst | 6 ++++-- doc/src/pair_eam.rst | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/doc/src/pair_adp.rst b/doc/src/pair_adp.rst index 6c4796fb85..bbfd98f677 100644 --- a/doc/src/pair_adp.rst +++ b/doc/src/pair_adp.rst @@ -56,8 +56,10 @@ command to specify them. * The NIST WWW site at http://www.ctcms.nist.gov/potentials. Note that ADP potentials obtained from NIST must be converted into the extended DYNAMO *setfl* format discussed below. -* The OpenKIM Project at https://openkim.org/browse/models/by-type provides - ADP potentials that can be used directly in LAMMPS with the :doc:`kim_commands interface `. +* The OpenKIM Project at + `https://openkim.org/browse/models/by-type `_ + provides ADP potentials that can be used directly in LAMMPS with the + :doc:`kim_commands ` interface. ---------- diff --git a/doc/src/pair_eam.rst b/doc/src/pair_eam.rst index 4710f8a9a1..7384a4d54c 100644 --- a/doc/src/pair_eam.rst +++ b/doc/src/pair_eam.rst @@ -149,6 +149,7 @@ potentials stored in DYNAMO or other formats: http://www.ctcms.nist.gov/potentials http://cst-www.nrl.navy.mil/ccm6/ap http://enpub.fulton.asu.edu/cms/potentials/main/main.htm + https://openkim.org These potentials should be usable with LAMMPS, though the alternate formats would need to be converted to the DYNAMO format used by LAMMPS @@ -156,6 +157,11 @@ and described on this page. The NIST site is maintained by Chandler Becker (cbecker at nist.gov) who is good resource for info on interatomic potentials and file formats. +The OpenKIM Project at +`https://openkim.org/browse/models/by-type `_ +provides EAM potentials that can be used directly in LAMMPS with the +:doc:`kim_commands ` interface. + ---------- For style *eam*\ , potential values are read from a file that is in the -- GitLab From d8a948d9b75bc21cb174e85a91070438a20416db Mon Sep 17 00:00:00 2001 From: Axel Kohlmeyer Date: Tue, 17 Mar 2020 21:13:03 -0400 Subject: [PATCH 055/577] correct spelling --- doc/src/kim_commands.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/kim_commands.rst b/doc/src/kim_commands.rst index aca2529ec7..99f7efffd5 100644 --- a/doc/src/kim_commands.rst +++ b/doc/src/kim_commands.rst @@ -49,7 +49,7 @@ Syntax on the prefix specified in *variable* and a number appended to indicate which element in the list of values is in the variable. *explicit* = returns the values separately in one more more variable names - provided as arguments that preceed *formatarg*\ . [default for *kim_param*] + provided as arguments that precede *formatarg*\ . [default for *kim_param*] * query_function = name of the OpenKIM web API query function to be used * queryargs = a series of *keyword=value* pairs that represent the web query; supported keywords depend on the query function -- GitLab From 8b75fb295039f005a4eeb073817cdaa792c56920 Mon Sep 17 00:00:00 2001 From: Yaser Afshar Date: Wed, 18 Mar 2020 16:56:47 -0500 Subject: [PATCH 056/577] initialize the python interpreter instance with python->init() --- src/KIM/kim_property.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/KIM/kim_property.cpp b/src/KIM/kim_property.cpp index 888aa4da0c..0a55d6aae9 100644 --- a/src/KIM/kim_property.cpp +++ b/src/KIM/kim_property.cpp @@ -65,6 +65,7 @@ #include "variable.h" #include "utils.h" #include "error.h" +#include "lmppython.h" #include @@ -81,10 +82,7 @@ kimProperty::kimProperty(LAMMPS *lmp) : Pointers(lmp) "3 >= 3.6 support."); #endif // one-time initialization of Python interpreter - if (!Py_IsInitialized()) { - Py_Initialize(); - PyEval_InitThreads(); - } + python->init(); #else error->all(FLERR, "Error Python support missing! Compile with PYTHON " "package installed!"); @@ -143,7 +141,7 @@ void kimProperty::command(int narg, char **arg) "\nkim-property Python package can be installed " "with pip:\n`pip install kim-property`\n" "See the installation instructions at\n" - "https://github.com/openkim/kim-property#installing-kim-property\n") + "https://github.com/openkim/kim-property#installing-kim-property\n" "for detailed information."); } -- GitLab From 986e5b746e1c9a2ed8e7fd3c0585ec693ca3961a Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Wed, 18 Mar 2020 16:40:29 -0600 Subject: [PATCH 057/577] new doc edits for refactored AtomVec styles --- doc/src/Modify.rst | 6 - doc/src/Modify_atom.rst | 274 +++++++++++-------- doc/src/atom_style.rst | 64 +++-- doc/src/compute_property_atom.rst | 86 +++--- doc/src/read_data.rst | 428 +++++++++++------------------- 5 files changed, 384 insertions(+), 474 deletions(-) diff --git a/doc/src/Modify.rst b/doc/src/Modify.rst index f875084d50..531fb6b1f3 100644 --- a/doc/src/Modify.rst +++ b/doc/src/Modify.rst @@ -10,7 +10,6 @@ If you add a new feature to LAMMPS and think it will be of interest to general users, we encourage you to submit it for inclusion in LAMMPS as a pull request on our `GitHub site `_, after reading the :doc:`Modify contribute ` doc page. - .. toctree:: :maxdepth: 1 @@ -33,8 +32,3 @@ as a pull request on our `GitHub site `_, afte Modify_body Modify_thermo Modify_variable - - -.. _lws: http://lammps.sandia.gov -.. _ld: Manual.html -.. _lc: Commands_all.html diff --git a/doc/src/Modify_atom.rst b/doc/src/Modify_atom.rst index d44a805161..64f44797b5 100644 --- a/doc/src/Modify_atom.rst +++ b/doc/src/Modify_atom.rst @@ -3,122 +3,168 @@ Atom styles Classes that define an :doc:`atom style ` are derived from the AtomVec class and managed by the Atom class. The atom style -determines what attributes are associated with an atom. A new atom -style can be created if one of the existing atom styles does not -define all the attributes you need to store and communicate with -atoms. +determines what attributes are associated with an atom and +communicated when it is a ghost atom or migrates to a new processor. +A new atom style can be created if one of the existing atom styles +does not define all the attributes you need to store and communicate +with atoms. -Atom\_vec\_atomic.cpp is a simple example of an atom style. +Atom\_vec\_atomic.cpp is the simplest example of an atom style. +Examining the code for others will make these instructions more clear. -Here is a brief description of methods you define in your new derived -class. See atom\_vec.h for details. +Note that the :doc:`atom style hybrid ` command can be +used to define atoms or particles which have the union of properties +of individual styles. Also the :doc:`fix property/atom ` command can be used to add a single property (e.g. charge +or a molecule ID) to a style that does not have it. It can also be +used to add custom properties to an atom, with options to communicate +them with ghost atoms or read them from a data file. Other LAMMPS +commands can access these custom properties, as can new pair, fix, +compute styles that are written to work with these properties. For +example, the :doc:`set ` command can be used to set the values of +custom per-atom properties from an input script. All of these methods +are less work than writing code for a new atom style. -+-------------------------+--------------------------------------------------------------------------------+ -| init | one time setup (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| grow | re-allocate atom arrays to longer lengths (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| grow\_reset | make array pointers in Atom and AtomVec classes consistent (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| copy | copy info for one atom to another atom's array locations (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_comm | store an atom's info in a buffer communicated every timestep (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_comm\_vel | add velocity info to communication buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_comm\_hybrid | store extra info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_comm | retrieve an atom's info from the buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_comm\_vel | also retrieve velocity info (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_comm\_hybrid | retrieve extra info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_reverse | store an atom's info in a buffer communicating partial forces (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_reverse\_hybrid | store extra info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_reverse | retrieve an atom's info from the buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_reverse\_hybrid | retrieve extra info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_border | store an atom's info in a buffer communicated on neighbor re-builds (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_border\_vel | add velocity info to buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_border\_hybrid | store extra info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_border | retrieve an atom's info from the buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_border\_vel | also retrieve velocity info (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_border\_hybrid | retrieve extra info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_exchange | store all an atom's info to migrate to another processor (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_exchange | retrieve an atom's info from the buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| size\_restart | number of restart quantities associated with proc's atoms (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| pack\_restart | pack atom quantities into a buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| unpack\_restart | unpack atom quantities from a buffer (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| create\_atom | create an individual atom of this style (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| data\_atom | parse an atom line from the data file (required) | -+-------------------------+--------------------------------------------------------------------------------+ -| data\_atom\_hybrid | parse additional atom info unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| data\_vel | parse one line of velocity information from data file (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| data\_vel\_hybrid | parse additional velocity data unique to this atom style (optional) | -+-------------------------+--------------------------------------------------------------------------------+ -| memory\_usage | tally memory allocated by atom arrays (required) | -+-------------------------+--------------------------------------------------------------------------------+ - -The constructor of the derived class sets values for several variables -that you must set when defining a new atom style, which are documented -in atom\_vec.h. New atom arrays are defined in atom.cpp. Search for -the word "customize" and you will find locations you will need to -modify. - -.. note:: - - It is possible to add some attributes, such as a molecule ID, to - atom styles that do not have them via the :doc:`fix property/atom ` command. This command also - allows new custom attributes consisting of extra integer or - floating-point values to be added to atoms. See the :doc:`fix property/atom ` doc page for examples of cases - where this is useful and details on how to initialize, access, and - output the custom values. - -New :doc:`pair styles `, :doc:`fixes `, or -:doc:`computes ` can be added to LAMMPS, as discussed below. -The code for these classes can use the per-atom properties defined by -fix property/atom. The Atom class has a find\_custom() method that is -useful in this context: - - -.. parsed-literal:: - - int index = atom->find_custom(char \*name, int &flag); - -The "name" of a custom attribute, as specified in the :doc:`fix property/atom ` command, is checked to verify -that it exists and its index is returned. The method also sets flag = -0/1 depending on whether it is an integer or floating-point attribute. -The vector of values associated with the attribute can then be -accessed using the returned index as - - -.. parsed-literal:: - - int \*ivector = atom->ivector[index]; - double \*dvector = atom->dvector[index]; - -Ivector or dvector are vectors of length Nlocal = # of owned atoms, -which store the attributes of individual atoms. +If you follow these directions your new style will automatically work +in tandem with others via the :doc:`atom_style hybrid ` +command. +The first step is to define a set of strings in the constructor of the +new derived class. Each string will have zero or more space-separated +variable names which are identical to those used in the atom.h header +file for per-atom properties. Note that some represent per-atom +vectors (q, molecule) while other are per-atom arrays (x,v). For all +but the last 2 strings you do not need to specify any of +(id,type,x,v,f). Those are included automatically as needed in the +other strings. + ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_grow | full list of properties which is allocated and stored | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_copy | list of properties to copy atoms are rearranged on-processor | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_comm | list of properties communicated to ghost atoms every step | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_comm\_vel | additional properties communicated if :doc:`comm_modify vel ` is used | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_reverse | list of properties summed from ghost atoms every step | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_border | list of properties communicated with ghost atoms every reneighboring step | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_border\_vel | additional properties communicated if :doc:`comm_modify vel ` is used | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_exchange | list of properties communicated when an atom migrates to another processor | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_restart | list of properties written/read to/from a restart file | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_create | list of properties defined when an atom is created by :doc:`create_atoms ` | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_data\_atom | list of properties (in order) in the Atoms section of a data file, as read by :doc:`read_data ` | ++-------------------------+--------------------------------------------------------------------------------+ +| fields\_data\_vel | list of properties (in order) in the Velocities section of a data file, as read by :doc:`read_data ` | ++-------------------------+--------------------------------------------------------------------------------+ + +In these strings you can list variable names which LAMMPS already +defines (in some other atom style), or you can create new variable +names. You should not re-use a LAMMPS variable for something with +different meaning in your atom style. If the meaning is related, but +interpreted differently by your atom style, then using the same +variable name means a user should not use your style and the other +style together in a :doc:`atom_style hybrid ` command. +Because there will only be one value of the variable and different +parts of LAMMPS will then likely use it differently. LAMMPS has +no way of checking for this. + +If you are defining new variable names then make them descriptive and +unique to your new atom style. For example choosing "e" for energy is +a bad choice; it is too generic. A better choice would be "e\_foo", +where "foo" is specific to your style. + +If any of the variable names in your new atom style do not exist in +LAMMPS, you need to add them to the src/atom.h and atom.cpp files. + +Search for the word "customize" or "customization" in these 2 files to +see where to add your variable. Adding a flag to the 2nd +customization section in atom.h is only necessary if your code (e.g. a +pair style) needs to check that a per-atom property is defined. These +flags should also be set in the constructor of the atom style child +class. + +In atom.cpp, aside from the constructor and destructor, there are 3 +methods that a new variable name or flag needs to be added to. + +In Atom::peratom\_create() when using the add_peratom() method, a +final length argument of 0 is for per-atom vectors, a length > 1 is +for per-atom arrays. Note the use of an extra per-thread flag and the +add_peratom_vary() method when last dimension of the array is +variable-length. + +Adding the variable name to Atom::extract() enable the per-atom data +to be accessed through the :doc:`LAMMPS library interface +` by a calling code, including from :doc:`Python +`. + +The constructor of the new atom style will also typically set a few +flags which are defined at the top of atom_vec.h. If these are +unclear, see how other atom styles use them. + +The grow_pointers() method is also required to make +a copy of peratom data pointers, as explained in the code. + +There are a number of other optional methods which your atom style can +implement. These are only needed if you need to do something +out-of-the-oridinary which the default operation of the AtomVec parent +class does not take care of. The best way to figure out why they are +sometimes useful is to look at how other atom styles use them. + +* process_args = use if the atom style has arguments +* init = called before each run +* force_clear = called before force computations each timestep + +A few atom styles define "bonus" data associated with some or all of +their particles, such as :doc:`atom_style ellipsoid or tri +`. These methods work with that data: + +* copy_bonus +* clear_bonus +* pack_comm_bonus +* unpack_comm_bonus +* pack_border_bonus +* unpack_border_bonus +* pack_exchange_bonus +* unpack_exchange_bonus +* size_restart_bonus +* pack_restart_bonus +* unpack_restart_bonus +* data_atom_bonus +* memory_usage_bonus -.. _lws: http://lammps.sandia.gov -.. _ld: Manual.html -.. _lc: Commands_all.html +The :doc:`atom_style body ` command can define a particle +geomerty with an arbitrary number of values. This method reads it +from a data file: + +* data_body + +These methods are called before or after operations handled by the +parent AtomVec class. They allow an atom style to do customized +operations on the per-atom values. For example :doc:`atom_style +sphere ` reads a diameter and density of each particle +from a data file. But these need to be converted internally to a +radius and mass. That operation is done in the data_\atom\_post() +method. + +* pack_restart_pre +* pack_restart_post +* unpack_restart_init +* create_atom_post +* data_atom_post +* pack_data_pre +* pack_data_post + +These methods enable the :doc:`compute property/atom ` command to access per-atom variables it does not +already define as arguments, so that they can be written to a dump +file or used by other LAMMPS commands. + +* property_atom +* pack_property_atom diff --git a/doc/src/atom_style.rst b/doc/src/atom_style.rst index d2ebc220d6..a44741f891 100644 --- a/doc/src/atom_style.rst +++ b/doc/src/atom_style.rst @@ -6,20 +6,21 @@ atom_style command Syntax """""" - .. code-block:: LAMMPS atom_style style args -* style = *angle* or *atomic* or *body* or *bond* or *charge* or *dipole* or *dpd* or *edpd* or *mdpd* or *tdpd* or *electron* or *ellipsoid* or *full* or *line* or *meso* or *molecular* or *peri* or *smd* or *sphere* or *spin* or *tri* or *template* or *hybrid* - +* style = *angle* or *atomic* or *body* or *bond* or *charge* or *dipole* or *dpd* or *edpd* or *electron* or *ellipsoid* or *full* or *line* or *mdpd* or *meso* or *molecular* or *peri* or *smd* or *sphere* or *spin* or *tdpd* or *tri* or *template* or *hybrid* + .. parsed-literal:: - + args = none for any style except the following *body* args = bstyle bstyle-args bstyle = style of body particles bstyle-args = additional arguments specific to the bstyle - see the :doc:`Howto body ` doc page for details + see the :doc:`Howto body ` doc + page for details + *sphere* arg = 0/1 (optional) for static/dynamic particle radii *tdpd* arg = Nspecies Nspecies = # of chemical species *template* arg = template-ID @@ -28,11 +29,9 @@ Syntax * accelerated styles (with same args) = *angle/kk* or *atomic/kk* or *bond/kk* or *charge/kk* or *full/kk* or *molecular/kk* - Examples """""""" - .. code-block:: LAMMPS atom_style atomic @@ -50,8 +49,8 @@ Description Define what style of atoms to use in a simulation. This determines what attributes are associated with the atoms. This command must be -used before a simulation is setup via a :doc:`read\_data `, -:doc:`read\_restart `, or :doc:`create\_box ` +used before a simulation is setup via a :doc:`read_data `, +:doc:`read_restart `, or :doc:`create_box ` command. .. note:: @@ -68,12 +67,12 @@ style more general than needed, though it may be slightly inefficient. The choice of style affects what quantities are stored by each atom, what quantities are communicated between processors to enable forces to be computed, and what quantities are listed in the data file read -by the :doc:`read\_data ` command. +by the :doc:`read_data ` command. These are the additional attributes of each style and the typical kinds of physical systems they are used to model. All styles store coordinates, velocities, atom IDs and types. See the -:doc:`read\_data `, :doc:`create\_atoms `, and +:doc:`read_data `, :doc:`create_atoms `, and :doc:`set ` commands for info on how to set these various quantities. @@ -94,10 +93,6 @@ quantities. +--------------+-----------------------------------------------------+--------------------------------------+ | *edpd* | temperature and heat capacity | eDPD particles | +--------------+-----------------------------------------------------+--------------------------------------+ -| *mdpd* | density | mDPD particles | -+--------------+-----------------------------------------------------+--------------------------------------+ -| *tdpd* | chemical concentration | tDPD particles | -+--------------+-----------------------------------------------------+--------------------------------------+ | *electron* | charge and spin and eradius | electronic force field | +--------------+-----------------------------------------------------+--------------------------------------+ | *ellipsoid* | shape, quaternion, angular momentum | aspherical particles | @@ -106,6 +101,8 @@ quantities. +--------------+-----------------------------------------------------+--------------------------------------+ | *line* | end points, angular velocity | rigid bodies | +--------------+-----------------------------------------------------+--------------------------------------+ +| *mdpd* | density | mDPD particles | ++--------------+-----------------------------------------------------+--------------------------------------+ | *meso* | rho, e, cv | SPH particles | +--------------+-----------------------------------------------------+--------------------------------------+ | *molecular* | bonds, angles, dihedrals, impropers | uncharged molecules | @@ -118,6 +115,8 @@ quantities. +--------------+-----------------------------------------------------+--------------------------------------+ | *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 | @@ -147,9 +146,16 @@ basis. For the *sphere* style, the particles are spheres and each stores a per-particle diameter and mass. If the diameter > 0.0, the particle is a finite-size sphere. If the diameter = 0.0, it is a point -particle. Note that by use of the *disc* keyword with the :doc:`fix nve/sphere `, :doc:`fix nvt/sphere `, -:doc:`fix nph/sphere `, :doc:`fix npt/sphere ` commands, spheres can be effectively -treated as 2d discs for a 2d simulation if desired. See also the :doc:`set density/disc ` command. +particle. Note that by use of the *disc* keyword with the :doc:`fix +nve/sphere `, :doc:`fix nvt/sphere `, +:doc:`fix nph/sphere `, :doc:`fix npt/sphere +` commands, spheres can be effectively treated as 2d +discs for a 2d simulation if desired. See also the :doc:`set +density/disc ` command. The *sphere* style takes an optional 0 +or 1 argument. A value of 0 means the radius of each sphere is +constant for the duration of the simulation. A value of 1 means the +radii may vary dynamically during the simulation, e.g. due to use of +the :doc:`fix adapt ` command. For the *ellipsoid* style, the particles are ellipsoids and each stores a flag which indicates whether it is a finite-size ellipsoid or @@ -173,7 +179,7 @@ per-particle mass and volume. The *dpd* style is for dissipative particle dynamics (DPD) particles. Note that it is part of the USER-DPD package, and is not for use with -the :doc:`pair\_style dpd or dpd/stat ` commands, which can +the :doc:`pair_style dpd or dpd/stat ` commands, which can simply use atom\_style atomic. Atom\_style dpd extends DPD particle properties with internal temperature (dpdTheta), internal conductive energy (uCond), internal mechanical energy (uMech), and internal @@ -240,7 +246,7 @@ can be advantageous for large-scale coarse-grained systems. another CO2, then you probably do not want each molecule file to define 2 atom types and a single bond type, because they will conflict with each other when a mixture system of H2O and CO2 molecules is - defined, e.g. by the :doc:`read\_data ` command. Rather the + defined, e.g. by the :doc:`read_data ` command. Rather the H2O molecule should define atom types 1 and 2, and bond type 1. And the CO2 molecule should define atom types 3 and 4 (or atom types 3 and 2 if a single oxygen type is desired), and bond type 2. @@ -262,10 +268,8 @@ Note that there may be additional arguments required along with the *bstyle* specification, in the atom\_style body command. These arguments are described on the :doc:`Howto body ` doc page. - ---------- - Typically, simulations require only a single (non-hybrid) atom style. If some atoms in the simulation do not have all the properties defined by a particular style, use the simplest style that defines all the @@ -287,10 +291,8 @@ per-atom basis. LAMMPS can be extended with new atom styles as well as new body styles; see the :doc:`Modify ` doc page. - ---------- - Styles with a *kk* suffix are functionally the same as the corresponding style without the suffix. They have been optimized to run faster, depending on your available hardware, as discussed in on @@ -315,9 +317,8 @@ instructions on how to use the accelerated styles effectively. Restrictions """""""""""" - This command cannot be used after the simulation box is defined by a -:doc:`read\_data ` or :doc:`create\_box ` command. +:doc:`read_data ` or :doc:`create_box ` command. Many of the styles listed above are only enabled if LAMMPS was built with a specific package, as listed below. See the :doc:`Build package ` doc page for more info. @@ -338,7 +339,7 @@ The *electron* style is part of the USER-EFF package for :doc:`electronic force The *dpd* style is part of the USER-DPD package for dissipative particle dynamics (DPD). -The *edpd*\ , *mdpd*\ , and *tdpd* styles are part of the USER-MESO package +The *edpd*\ , *mdpd*\ , and *tdpd* styles are part of the USER-MESODPD package for energy-conserving dissipative particle dynamics (eDPD), many-body dissipative particle dynamics (mDPD), and transport dissipative particle dynamics (tDPD), respectively. @@ -354,20 +355,17 @@ The *wavepacket* style is part of the USER-AWPMD package for the Related commands """""""""""""""" -:doc:`read\_data `, :doc:`pair\_style ` +:doc:`read_data `, :doc:`pair_style ` Default """"""" -atom\_style atomic - +The default atom style is atomic. If atom\_style sphere is used its +default argument is 0. ---------- - .. _Grime: - - **(Grime)** Grime and Voth, to appear in J Chem Theory & Computation (2014). diff --git a/doc/src/compute_property_atom.rst b/doc/src/compute_property_atom.rst index f78798e6f5..0ce0f32e96 100644 --- a/doc/src/compute_property_atom.rst +++ b/doc/src/compute_property_atom.rst @@ -6,7 +6,6 @@ compute property/atom command Syntax """""" - .. parsed-literal:: compute ID group-ID property/atom input1 input2 ... @@ -14,9 +13,9 @@ Syntax * ID, group-ID are documented in :doc:`compute ` command * property/atom = style name of this compute command * input = one or more atom attributes - + .. parsed-literal:: - + possible attributes = id, mol, proc, type, mass, x, y, z, xs, ys, zs, xu, yu, zu, ix, iy, iz, vx, vy, vz, fx, fy, fz, @@ -36,9 +35,8 @@ Syntax rho, drho, e, de, cv, i_name, d_name - .. parsed-literal:: - + id = atom ID mol = molecule ID proc = ID of processor that owns atom @@ -66,46 +64,39 @@ Syntax corner123x, corner123y, corner123z = corner points of triangle nbonds = number of bonds assigned to an atom - .. parsed-literal:: - + PERI package per-atom properties: - vfrac = ??? - s0 = ??? + vfrac = volume fraction + s0 = max stretch of any bond a particle is part of - .. parsed-literal:: - + USER-EFF and USER-AWPMD package per-atom properties: spin = electron spin eradius = electron radius ervel = electron radial velocity erforce = electron radial force - .. parsed-literal:: - + USER-SPH package per-atom properties: - rho = ??? - drho = ??? - e = ??? - de = ??? - cv = ??? + rho = density of SPH particles + drho = change in density + e = energy + de = change in thermal energy + cv = heat capacity - .. parsed-literal:: - + :doc:`fix property/atom ` per-atom properties: i_name = custom integer vector with name d_name = custom integer vector with name - - Examples """""""" - -.. parsed-literal:: +.. code-block:: LAMMPS compute 1 all property/atom xs vx fx mux compute 2 all property/atom type @@ -117,13 +108,17 @@ Description Define a computation that simply stores atom attributes 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 list of possible attributes is the same as that used by the :doc:`dump custom ` command, which describes their meaning, with some -additional quantities that are only defined for certain :doc:`atom styles `. Basically, this augmented list gives an -input script access to any per-atom quantity stored by LAMMPS. +: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 list of possible attributes is the same as that used by the +:doc:`dump custom ` command, which describes their meaning, with +some additional quantities that are only defined for certain +:doc:`atom styles `. Basically, this augmented list gives +an input script access to any per-atom quantity stored by LAMMPS. 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 @@ -141,8 +136,9 @@ particles and body particles and store the 4-vector quaternion representing the orientation of each particle. See the :doc:`set ` command for an explanation of the quaternion vector. -*End1x*\ , *end1y*\ , *end1z*\ , *end2x*\ , *end2y*\ , *end2z*\ , are defined for -line segment particles and define the end points of each line segment. +*End1x*\ , *end1y*\ , *end1z*\ , *end2x*\ , *end2y*\ , *end2z*\ , are +defined for line segment particles and define the end points of each +line segment. *Corner1x*\ , *corner1y*\ , *corner1z*\ , *corner2x*\ , *corner2y*\ , *corner2z*\ , *corner3x*\ , *corner3y*\ , *corner3z*\ , are defined for @@ -153,14 +149,14 @@ number of explicit bonds assigned to an atom. Note that if the :doc:`newton bond ` command is set to *on*\ , which is the default, then every bond in the system is assigned to only one of the two atoms in the bond. Thus a bond between atoms I,J may be tallied -for either atom I or atom J. If :doc:`newton bond off ` is set, -it will be tallied with both atom I and atom J. +for either atom I or atom J. If :doc:`newton bond off ` is +set, it will be tallied with both atom I and atom J. The *i\_name* and *d\_name* attributes refer to custom integer and floating-point properties that have been added to each atom via the -:doc:`fix property/atom ` command. When that command -is used specific names are given to each attribute which are what is -specified as the "name" portion of *i\_name* or *d\_name*. +:doc:`fix property/atom ` command. When that +command is used specific names are given to each attribute which are +what is specified as the "name" portion of *i\_name* or *d\_name*. **Output info:** @@ -169,8 +165,8 @@ 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 ` doc page for an overview of LAMMPS output -options. +per-atom values from a compute as input. See the :doc:`Howto output +` doc 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. velocity units for vx, charge @@ -187,12 +183,8 @@ Restrictions Related commands """""""""""""""" -:doc:`dump custom `, :doc:`compute reduce `, :doc:`fix ave/atom `, :doc:`fix ave/chunk `, -:doc:`fix property/atom ` +:doc:`dump custom `, :doc:`compute reduce `, +:doc::doc:`fix ave/atom `, :doc:`fix ave/chunk +:doc:`, `fix property/atom ` **Default:** none - - -.. _lws: http://lammps.sandia.gov -.. _ld: Manual.html -.. _lc: Commands_all.html diff --git a/doc/src/read_data.rst b/doc/src/read_data.rst index 798f95e5ec..410a372a34 100644 --- a/doc/src/read_data.rst +++ b/doc/src/read_data.rst @@ -1,22 +1,21 @@ -.. index:: read\_data +.. index:: read_data -read\_data command -================== +read_data command +================= Syntax """""" - -.. parsed-literal:: +.. code-block:: LAMMPS read_data file keyword args ... * 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* - + .. parsed-literal:: - + *add* arg = *append* or *IDoffset* or *IDoffset MOLoffset* or *merge* append = add new atoms with atom IDs appended to current IDs IDoffset = add new atoms with atom IDs having IDoffset added @@ -48,13 +47,10 @@ Syntax header-string = header lines containing this string will be passed to fix section-string = section names with this string will be passed to fix - - Examples """""""" - -.. parsed-literal:: +.. code-block:: LAMMPS read_data data.lj read_data ../run7/data.polymer.gz @@ -68,8 +64,8 @@ Description Read in a data file containing information LAMMPS needs to run a simulation. The file can be ASCII text or a gzipped text file (detected by a .gz suffix). This is one of 3 ways to specify initial -atom coordinates; see the :doc:`read\_restart ` and -:doc:`create\_atoms ` commands for alternative methods. +atom coordinates; see the :doc:`read_restart ` and +:doc:`create_atoms ` commands for alternative methods. Also see the explanation of the :doc:`-restart command-line switch ` which can convert a restart file to a data file. @@ -83,7 +79,7 @@ specified group-ID. The group will be created if it does not already exist. This is useful if you are reading multiple data files and wish to put sets of atoms into different groups so they can be operated on later. E.g. a group of added atoms can be moved to new positions via -the :doc:`displace\_atoms ` command. Note that atoms +the :doc:`displace_atoms ` command. Note that atoms read from the data file are also always added to the "all" group. The :doc:`group ` command discusses atom groups, as used in LAMMPS. @@ -95,10 +91,8 @@ styles defined, or to read a data file for a different force field. The use of the *fix* keyword is discussed below. - ---------- - **Reading multiple data files** The read\_data command can be used multiple times with the same or @@ -107,7 +101,7 @@ contained in individual data files. For example one data file could contain fluid in a confined domain; a second could contain wall atoms, and the second file could be read a third time to create a wall on the other side of the fluid. The third set of atoms could be rotated to -an opposing direction using the :doc:`displace\_atoms ` +an opposing direction using the :doc:`displace_atoms ` command, after the third read\_data command is used. The *add*\ , *offset*\ , *shift*\ , *extra*\ , and *group* keywords are @@ -116,7 +110,7 @@ useful in this context. If a simulation box does not yet exist, the *add* keyword cannot be used; the read\_data command is being used for the first time. If a simulation box does exist, due to using the -:doc:`create\_box ` command, or a previous read\_data command, +:doc:`create_box ` command, or a previous read\_data command, then the *add* keyword must be used. .. note:: @@ -175,9 +169,9 @@ for a 2d simulation. This is a mechanism for adding structured collections of atoms at different locations within the simulation box, to build up a complex geometry. It is up to you to insure atoms do not end up overlapping unphysically which would lead to bad dynamics. -Note that the :doc:`displace\_atoms ` command can be used +Note that the :doc:`displace_atoms ` command can be used to move a subset of atoms after they have been read from a data file. -Likewise, the :doc:`delete\_atoms ` command can be used to +Likewise, the :doc:`delete_atoms ` command can be used to remove overlapping atoms. Note that the shift values (Sx, Sy, Sz) are also added to the simulation box information (xlo, xhi, ylo, yhi, zlo, zhi) in the data file to shift its boundaries. E.g. xlo\_new = xlo + @@ -212,17 +206,15 @@ interactions in your input script to have a complete pairwise interaction model. An alternative to using the *extra* keywords with the read\_data -command, is to use the :doc:`create\_box ` command to +command, is to use the :doc:`create_box ` command to initialize the simulation box and all the various type limits you need via its *extra* keywords. Then use the read\_data command one or more times to populate the system with atoms, bonds, angles, etc, using the *offset* keyword if desired to alter types used in the various data files you read. - ---------- - **Format of a data file** The structure of the data file is important, though many settings and @@ -266,10 +258,8 @@ be capitalized as shown and can't have extra white-space between their words - e.g. two spaces or a tab between the 2 words in "xlo xhi" or the 2 words in "Bond Coeffs", is not valid. - ---------- - **Format of the header of a data file** These are the recognized header keywords. Header lines can come in @@ -408,7 +398,7 @@ molecules defined in the data file. Using this header flag is deprecated; please use the *extra/special/per/atom* keyword instead. Using this setting will pre-allocate space in the LAMMPS data structures for storing these neighbors. See the -:doc:`special\_bonds ` and :doc:`molecule ` doc +:doc:`special_bonds ` and :doc:`molecule ` doc pages for more discussion of 1-2,1-3,1-4 neighbors. .. note:: @@ -421,7 +411,7 @@ pages for more discussion of 1-2,1-3,1-4 neighbors. If they appear in later data files, they are ignored. The "ellipsoids" and "lines" and "triangles" and "bodies" settings are -only used with :doc:`atom\_style ellipsoid or line or tri or body ` and specify how many of the atoms are +only used with :doc:`atom_style ellipsoid or line or tri or body ` and specify how many of the atoms are finite-size ellipsoids or lines or triangles or bodies; the remainder are point particles. See the discussion of ellipsoidflag and the *Ellipsoids* section below. See the discussion of lineflag and the @@ -431,7 +421,7 @@ are point particles. See the discussion of ellipsoidflag and the .. note:: - For :doc:`atom\_style template `, the molecular + For :doc:`atom_style template `, the molecular topology (bonds,angles,etc) is contained in the molecule templates read-in by the :doc:`molecule ` command. This means you cannot set the *bonds*\ , *angles*\ , etc header keywords in the data @@ -440,10 +430,8 @@ are point particles. See the discussion of ellipsoidflag and the keywords, though it is not necessary. If specified, they must match the maximum values defined in any of the template molecules. - ---------- - **Format of the body of a data file** These are the section keywords for the body of the file. @@ -460,14 +448,13 @@ currently defined style: For example, these lines: - .. parsed-literal:: Atoms # sphere Pair Coeffs # lj/cut -will check if the currently-defined :doc:`atom\_style ` is -*sphere*\ , and the current :doc:`pair\_style ` is *lj/cut*\ . +will check if the currently-defined :doc:`atom_style ` is +*sphere*\ , and the current :doc:`pair_style ` is *lj/cut*\ . If not, LAMMPS will issue a warning to indicate that the data file section likely does not contain the correct number or type of parameters expected for the currently-defined style. @@ -480,93 +467,76 @@ Any individual line in the various sections can have a trailing comment starting with "#" for annotation purposes. E.g. in the Atoms section: - .. parsed-literal:: 10 1 17 -1.0 10.0 5.0 6.0 # salt ion - ---------- - *Angle Coeffs* section: * one line per angle type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = angle type (1-N) coeffs = list of coeffs * example: - - .. parsed-literal:: - - 6 70 108.5 0 0 + .. parsed-literal:: + 6 70 108.5 0 0 The number and meaning of the coefficients are specific to the defined -angle style. See the :doc:`angle\_style ` and -:doc:`angle\_coeff ` commands for details. Coefficients can -also be set via the :doc:`angle\_coeff ` command in the +angle style. See the :doc:`angle_style ` and +:doc:`angle_coeff ` commands for details. Coefficients can +also be set via the :doc:`angle_coeff ` command in the input script. - ---------- - *AngleAngle Coeffs* section: * one line per improper type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = improper type (1-N) coeffs = list of coeffs (see :doc:`improper_coeff `) - - - ---------- - *AngleAngleTorsion Coeffs* section: * one line per dihedral type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = dihedral type (1-N) coeffs = list of coeffs (see :doc:`dihedral_coeff `) - - - ---------- - *Angles* section: * one line per angle * line syntax: ID type atom1 atom2 atom3 - + .. parsed-literal:: - + ID = number of angle (1-Nangles) type = angle type (1-Nangletype) atom1,atom2,atom3 = IDs of 1st,2nd,3rd atoms in angle example: - - .. parsed-literal:: - - 2 2 17 29 430 + .. parsed-literal:: + 2 2 17 29 430 The 3 atoms are ordered linearly within the angle. Thus the central atom (around which the angle is computed) is the atom2 in the list. @@ -574,26 +544,20 @@ E.g. H,O,H for a water molecule. The *Angles* section must appear after the *Atoms* section. All values in this section must be integers (1, not 1.0). - ---------- - *AngleTorsion Coeffs* section: * one line per dihedral type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = dihedral type (1-N) coeffs = list of coeffs (see :doc:`dihedral_coeff `) - - - ---------- - *Atoms* section: * one line per atom @@ -624,10 +588,6 @@ of analysis. +------------+---------------------------------------------------------------------------+ | edpd | atom-ID atom-type edpd\_temp edpd\_cv x y z | +------------+---------------------------------------------------------------------------+ -| mdpd | atom-ID atom-type rho x y z | -+------------+---------------------------------------------------------------------------+ -| tdpd | atom-ID atom-type x y z cc1 cc2 ... ccNspecies | -+------------+---------------------------------------------------------------------------+ | electron | atom-ID atom-type q spin eradius x y z | +------------+---------------------------------------------------------------------------+ | ellipsoid | atom-ID atom-type ellipsoidflag density x y z | @@ -636,17 +596,22 @@ of analysis. +------------+---------------------------------------------------------------------------+ | line | atom-ID molecule-ID atom-type lineflag density x y z | +------------+---------------------------------------------------------------------------+ +| mdpd | atom-ID atom-type rho x y z | ++------------+---------------------------------------------------------------------------+ | meso | atom-ID atom-type rho e cv x y z | +------------+---------------------------------------------------------------------------+ | molecular | atom-ID molecule-ID atom-type x y z | +------------+---------------------------------------------------------------------------+ | peri | atom-ID atom-type volume density x y z | +------------+---------------------------------------------------------------------------+ -| smd | atom-ID atom-type molecule volume mass kernel-radius contact-radius x y z | +| smd | atom-ID atom-type molecule volume mass kernel-radius +contact-radius x0 y0 z0 x y z | +------------+---------------------------------------------------------------------------+ | sphere | atom-ID atom-type diameter density x y z | +------------+---------------------------------------------------------------------------+ -| spin | atom-ID atom-type sp x y z spx spy spz | +| spin | atom-ID atom-type x y z spx spy spz sp | ++------------+---------------------------------------------------------------------------+ +| tdpd | atom-ID atom-type x y z cc1 cc2 ... ccNspecies | +------------+---------------------------------------------------------------------------+ | template | atom-ID molecule-ID template-index template-atom atom-type x y z | +------------+---------------------------------------------------------------------------+ @@ -662,7 +627,7 @@ The per-atom values have these meanings and units, listed alphabetically: * atom-ID = integer ID of atom * atom-type = type of atom (1-Ntype) * bodyflag = 1 for body particles, 0 for point particles -* cc = chemical concentration for tDPD particles for each species (mole/volume units) +* ccN = chemical concentration for tDPD particles for each species (mole/volume units) * contact-radius = ??? (distance units) * cs\_re,cs\_im = real/imaginary parts of wave packet coefficients * cv = heat capacity (need units) for SPH particles @@ -682,14 +647,15 @@ The per-atom values have these meanings and units, listed alphabetically: * q = charge on atom (charge units) * rho = density (need units) for SPH particles * spin = electron spin (+1/-1), 0 = nuclei, 2 = fixed-core, 3 = pseudo-cores (i.e. ECP) -* sp = norm of magnetic spin of atom (in number of Bohr magnetons) -* spx,spy,spz = components of magnetic spin of atom (adim normalized vector) +* sp = magnitude of magnetic spin of atom (Bohr magnetons) +* spx,spy,spz = components of magnetic spin of atom (unit vector) * template-atom = which atom within a template molecule the atom is * template-index = which molecule within the molecule template the atom is part of * theta = internal temperature of a DPD particle * triangleflag = 1 for triangular particles, 0 for point or spherical particles * volume = volume of Peridynamic particle (distance\^3 units) * x,y,z = coordinates of atom (distance units) +* x0,y0,z0 = original (strain-free) coordinates of atom (distance units) The units for these quantities depend on the unit style; see the :doc:`units ` command for details. @@ -702,7 +668,7 @@ in dump files. Normally, it is a unique value from 1 to Natoms for each atom. Unique values larger than Natoms can be used, but they will cause extra memory to be allocated on each processor, if an atom map array is used, but not if an atom map hash is used; see the -:doc:`atom\_modify ` command for details. If an atom map is +:doc:`atom_modify ` command for details. If an atom map is not used (e.g. an atomic system with no bonds), and you don't care if unique atom IDs appear in dump files, then the atom-IDs can all be set to 0. @@ -723,7 +689,7 @@ triangle, or body in the corresponding *Ellipsoids*\ , *Lines*\ , *Triangles*\ , or *Bodies* section. The *template-index* and *template-atom* are only defined used by -:doc:`atom\_style template `. In this case the +:doc:`atom_style template `. In this case the :doc:`molecule ` command is used to define a molecule template which contains one or more molecules. If an atom belongs to one of those molecules, its *template-index* and *template-atom* are both set @@ -754,15 +720,14 @@ used. A *disc* keyword can also be used with time integration fixes, such as :doc:`fix nve/sphere ` and :doc:`fix nvt/sphere ` to time integrate their motion as 2d discs (not 3d spheres), by changing their moment of inertia. -For atom\_style hybrid, following the 5 initial values (ID,type,x,y,z), -specific values for each sub-style must be listed. The order of the -sub-styles is the same as they were listed in the -:doc:`atom\_style ` command. The sub-style specific values -are those that are not the 5 standard ones (ID,type,x,y,z). For -example, for the "charge" sub-style, a "q" value would appear. For -the "full" sub-style, a "molecule-ID" and "q" would appear. These are -listed in the same order they appear as listed above. Thus if - +For atom\_style hybrid, following the 5 initial values +(ID,type,x,y,z), specific values for each sub-style must be listed. +The order of the sub-styles is the same as they were listed in the +:doc:`atom_style ` command. The specific values for each +sub-style are those that are not the 5 standard ones (ID,type,x,y,z). +For example, for the "charge" sub-style, a "q" value would appear. +For the "full" sub-style, a "molecule-ID" and "q" would appear. These +are listed in the same order they appear as listed above. Thus if .. parsed-literal:: @@ -770,19 +735,19 @@ listed in the same order they appear as listed above. Thus if were used in the input script, each atom line would have these fields: - .. parsed-literal:: atom-ID atom-type x y z q diameter density Note that if a non-standard value is defined by multiple sub-styles, -it must appear multiple times in the atom line. E.g. the atom line -for atom\_style hybrid dipole full would list "q" twice: - +it only appears once in the atom line. E.g. the atom line for +atom\_style hybrid dipole full would list "q" only once, with the +dipole sub-style fields; "q" does not appear with the full sub-style +fields. .. parsed-literal:: - atom-ID atom-type x y z q mux muy myz molecule-ID q + atom-ID atom-type x y z q mux muy myz molecule-ID Atom lines specify the (x,y,z) coordinates of atoms. These can be inside or outside the simulation box. When the data file is read, @@ -827,7 +792,6 @@ that use unwrapped coordinates internally are as follows: continued run (restarted from a data file) begins with image flags that are consistent with the previous run. - .. note:: If your system is an infinite periodic crystal with bonds then @@ -841,41 +805,37 @@ a *Velocities* section in the data file or by a :doc:`velocity ` or :doc:`set ` command in the input script. - ---------- - *Bodies* section: * one or more lines per body * first line syntax: atom-ID Ninteger Ndouble - + .. parsed-literal:: - + Ninteger = # of integer quantities for this particle Ndouble = # of floating-point quantities for this particle * 0 or more integer lines with total of Ninteger values * 0 or more double lines with total of Ndouble values * example: - + .. parsed-literal:: - + 12 3 6 2 3 2 1.0 2.0 3.0 1.0 2.0 4.0 * example: - + .. parsed-literal:: - + 12 0 14 1.0 2.0 3.0 1.0 2.0 4.0 1.0 2.0 3.0 1.0 2.0 4.0 4.0 2.0 - - -The *Bodies* section must appear if :doc:`atom\_style body ` +The *Bodies* section must appear if :doc:`atom_style body ` is used and any atoms listed in the *Atoms* section have a bodyflag = 1. The number of bodies should be specified in the header section via the "bodies" keyword. @@ -883,7 +843,7 @@ the "bodies" keyword. Each body can have a variable number of integer and/or floating-point values. The number and meaning of the values is defined by the body style, as described in the :doc:`Howto body ` doc page. The -body style is given as an argument to the :doc:`atom\_style body ` command. +body style is given as an argument to the :doc:`atom_style body ` command. The Ninteger and Ndouble values determine how many integer and floating-point values are specified for this particle. Ninteger and @@ -896,187 +856,155 @@ particular type, no lines appear for that type. The *Bodies* section must appear after the *Atoms* section. - ---------- - *Bond Coeffs* section: * one line per bond type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = bond type (1-N) coeffs = list of coeffs * example: - - .. parsed-literal:: - - 4 250 1.49 + .. parsed-literal:: + 4 250 1.49 The number and meaning of the coefficients are specific to the defined -bond style. See the :doc:`bond\_style ` and -:doc:`bond\_coeff ` commands for details. Coefficients can -also be set via the :doc:`bond\_coeff ` command in the input +bond style. See the :doc:`bond_style ` and +:doc:`bond_coeff ` commands for details. Coefficients can +also be set via the :doc:`bond_coeff ` command in the input script. - ---------- - *BondAngle Coeffs* section: * one line per angle type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = angle type (1-N) coeffs = list of coeffs (see class 2 section of :doc:`angle_coeff `) - - - ---------- - *BondBond Coeffs* section: * one line per angle type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = angle type (1-N) coeffs = list of coeffs (see class 2 section of :doc:`angle_coeff `) - - - ---------- - *BondBond13 Coeffs* section: * one line per dihedral type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = dihedral type (1-N) coeffs = list of coeffs (see class 2 section of :doc:`dihedral_coeff `) - - - ---------- - *Bonds* section: * one line per bond * line syntax: ID type atom1 atom2 - + .. parsed-literal:: - + ID = bond number (1-Nbonds) type = bond type (1-Nbondtype) atom1,atom2 = IDs of 1st,2nd atoms in bond * example: - - .. parsed-literal:: - - 12 3 17 29 + .. parsed-literal:: + 12 3 17 29 The *Bonds* section must appear after the *Atoms* section. All values in this section must be integers (1, not 1.0). - ---------- - *Dihedral Coeffs* section: * one line per dihedral type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = dihedral type (1-N) coeffs = list of coeffs * example: - - .. parsed-literal:: - - 3 0.6 1 0 1 + .. parsed-literal:: + 3 0.6 1 0 1 The number and meaning of the coefficients are specific to the defined -dihedral style. See the :doc:`dihedral\_style ` and -:doc:`dihedral\_coeff ` commands for details. +dihedral style. See the :doc:`dihedral_style ` and +:doc:`dihedral_coeff ` commands for details. Coefficients can also be set via the -:doc:`dihedral\_coeff ` command in the input script. - +:doc:`dihedral_coeff ` command in the input script. ---------- - *Dihedrals* section: * one line per dihedral * line syntax: ID type atom1 atom2 atom3 atom4 - + .. parsed-literal:: - + ID = number of dihedral (1-Ndihedrals) type = dihedral type (1-Ndihedraltype) atom1,atom2,atom3,atom4 = IDs of 1st,2nd,3rd,4th atoms in dihedral * example: - - .. parsed-literal:: - - 12 4 17 29 30 21 + .. parsed-literal:: + 12 4 17 29 30 21 The 4 atoms are ordered linearly within the dihedral. The *Dihedrals* section must appear after the *Atoms* section. All values in this section must be integers (1, not 1.0). - ---------- - *Ellipsoids* section: * one line per ellipsoid * line syntax: atom-ID shapex shapey shapez quatw quati quatj quatk - + .. parsed-literal:: - + atom-ID = ID of atom which is an ellipsoid shapex,shapey,shapez = 3 diameters of ellipsoid (distance units) quatw,quati,quatj,quatk = quaternion components for orientation of atom * example: - - .. parsed-literal:: - - 12 1 2 1 1 0 0 0 + .. parsed-literal:: + 12 1 2 1 1 0 0 0 -The *Ellipsoids* section must appear if :doc:`atom\_style ellipsoid ` is used and any atoms are listed in the +The *Ellipsoids* section must appear if :doc:`atom_style ellipsoid ` is used and any atoms are listed in the *Atoms* section with an ellipsoidflag = 1. The number of ellipsoids should be specified in the header section via the "ellipsoids" keyword. @@ -1099,72 +1027,60 @@ specified as a unit vector. The *Ellipsoids* section must appear after the *Atoms* section. - ---------- - *EndBondTorsion Coeffs* section: * one line per dihedral type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = dihedral type (1-N) coeffs = list of coeffs (see class 2 section of :doc:`dihedral_coeff `) - - - ---------- - *Improper Coeffs* section: * one line per improper type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = improper type (1-N) coeffs = list of coeffs * example: - - .. parsed-literal:: - - 2 20 0.0548311 + .. parsed-literal:: + 2 20 0.0548311 The number and meaning of the coefficients are specific to the defined -improper style. See the :doc:`improper\_style ` and -:doc:`improper\_coeff ` commands for details. +improper style. See the :doc:`improper_style ` and +:doc:`improper_coeff ` commands for details. Coefficients can also be set via the -:doc:`improper\_coeff ` command in the input script. - +:doc:`improper_coeff ` command in the input script. ---------- - *Impropers* section: * one line per improper * line syntax: ID type atom1 atom2 atom3 atom4 - + .. parsed-literal:: - + ID = number of improper (1-Nimpropers) type = improper type (1-Nimpropertype) atom1,atom2,atom3,atom4 = IDs of 1st,2nd,3rd,4th atoms in improper * example: - - .. parsed-literal:: - - 12 3 17 29 13 100 + .. parsed-literal:: + 12 3 17 29 13 100 The ordering of the 4 atoms determines the definition of the improper angle used in the formula for each :doc:`improper style `. See the doc pages for individual styles @@ -1173,30 +1089,26 @@ for details. The *Impropers* section must appear after the *Atoms* section. All values in this section must be integers (1, not 1.0). - ---------- - *Lines* section: * one line per line segment * line syntax: atom-ID x1 y1 x2 y2 - + .. parsed-literal:: - + atom-ID = ID of atom which is a line segment x1,y1 = 1st end point x2,y2 = 2nd end point * example: - - .. parsed-literal:: - - 12 1.0 0.0 2.0 0.0 + .. parsed-literal:: + 12 1.0 0.0 2.0 0.0 -The *Lines* section must appear if :doc:`atom\_style line ` +The *Lines* section must appear if :doc:`atom_style line ` is used and any atoms are listed in the *Atoms* section with a lineflag = 1. The number of lines should be specified in the header section via the "lines" keyword. @@ -1210,139 +1122,119 @@ for defining some interactions. The *Lines* section must appear after the *Atoms* section. - ---------- - *Masses* section: * one line per atom type * line syntax: ID mass - + .. parsed-literal:: - + ID = atom type (1-N) mass = mass value * example: - - .. parsed-literal:: - - 3 1.01 + .. parsed-literal:: + 3 1.01 This defines the mass of each atom type. This can also be set via the :doc:`mass ` command in the input script. This section cannot be used for atom styles that define a mass for individual atoms - -e.g. :doc:`atom\_style sphere `. - +e.g. :doc:`atom_style sphere `. ---------- - *MiddleBondTorsion Coeffs* section: * one line per dihedral type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = dihedral type (1-N) coeffs = list of coeffs (see class 2 section of :doc:`dihedral_coeff `) - - - ---------- - *Pair Coeffs* section: * one line per atom type * line syntax: ID coeffs - + .. parsed-literal:: - + ID = atom type (1-N) coeffs = list of coeffs * example: - - .. parsed-literal:: - - 3 0.022 2.35197 0.022 2.35197 + .. parsed-literal:: + 3 0.022 2.35197 0.022 2.35197 The number and meaning of the coefficients are specific to the defined -pair style. See the :doc:`pair\_style ` and -:doc:`pair\_coeff ` commands for details. Since pair +pair style. See the :doc:`pair_style ` and +:doc:`pair_coeff ` commands for details. Since pair coefficients for types I != J are not specified, these will be generated automatically by the pair style's mixing rule. See the -individual pair\_style doc pages and the :doc:`pair\_modify mix ` command for details. Pair coefficients can also -be set via the :doc:`pair\_coeff ` command in the input +individual pair\_style doc pages and the :doc:`pair_modify mix ` command for details. Pair coefficients can also +be set via the :doc:`pair_coeff ` command in the input script. - ---------- - *PairIJ Coeffs* section: * one line per pair of atom types for all I,J with I <= J * line syntax: ID1 ID2 coeffs - + .. parsed-literal:: - + ID1 = atom type I = 1-N ID2 = atom type J = I-N, with I <= J coeffs = list of coeffs * examples: - + .. parsed-literal:: - + 3 3 0.022 2.35197 0.022 2.35197 3 5 0.022 2.35197 0.022 2.35197 - - This section must have N\*(N+1)/2 lines where N = # of atom types. The number and meaning of the coefficients are specific to the defined -pair style. See the :doc:`pair\_style ` and -:doc:`pair\_coeff ` commands for details. Since pair +pair style. See the :doc:`pair_style ` and +:doc:`pair_coeff ` commands for details. Since pair coefficients for types I != J are all specified, these values will turn off the default mixing rule defined by the pair style. See the -individual pair\_style doc pages and the :doc:`pair\_modify mix ` command for details. Pair coefficients can also -be set via the :doc:`pair\_coeff ` command in the input +individual pair\_style doc pages and the :doc:`pair_modify mix ` command for details. Pair coefficients can also +be set via the :doc:`pair_coeff ` command in the input script. - ---------- - *Triangles* section: * one line per triangle * line syntax: atom-ID x1 y1 z1 x2 y2 z2 x3 y3 z3 - + .. parsed-literal:: - + atom-ID = ID of atom which is a line segment x1,y1,z1 = 1st corner point x2,y2,z2 = 2nd corner point x3,y3,z3 = 3rd corner point * example: - - .. parsed-literal:: - - 12 0.0 0.0 0.0 2.0 0.0 1.0 0.0 2.0 1.0 + .. parsed-literal:: + 12 0.0 0.0 0.0 2.0 0.0 1.0 0.0 2.0 1.0 -The *Triangles* section must appear if :doc:`atom\_style tri ` is used and any atoms are listed in the *Atoms* +The *Triangles* section must appear if :doc:`atom_style tri ` is used and any atoms are listed in the *Atoms* section with a triangleflag = 1. The number of lines should be specified in the header section via the "triangles" keyword. @@ -1354,10 +1246,8 @@ orientation may be important for defining some interactions. The *Triangles* section must appear after the *Atoms* section. - ---------- - *Velocities* section: * one line per atom @@ -1394,21 +1284,19 @@ Wz are in units of angular velocity (radians/time). For atom\_style hybrid, following the 4 initial values (ID,vx,vy,vz), specific values for each sub-style must be listed. The order of the sub-styles is the same as they were listed in the -:doc:`atom\_style ` command. The sub-style specific values +:doc:`atom_style ` command. The sub-style specific values are those that are not the 5 standard ones (ID,vx,vy,vz). For example, for the "sphere" sub-style, "wx", "wy", "wz" values would appear. These are listed in the same order they appear as listed above. Thus if - -.. parsed-literal:: +.. code-block:: LAMMPS atom_style hybrid electron sphere were used in the input script, each velocity line would have these fields: - .. parsed-literal:: atom-ID vx vy vz ervel wx wy wz @@ -1416,14 +1304,11 @@ fields: Translational velocities can also be set by the :doc:`velocity ` command in the input script. - ---------- - Restrictions """""""""""" - To read gzipped data files, you must compile LAMMPS with the -DLAMMPS\_GZIP option. See the :doc:`Build settings ` doc page for details. @@ -1431,15 +1316,10 @@ doc page for details. Related commands """""""""""""""" -:doc:`read\_dump `, :doc:`read\_restart `, -:doc:`create\_atoms `, :doc:`write\_data ` +:doc:`read_dump `, :doc:`read_restart `, +:doc:`create_atoms `, :doc:`write_data ` Default """"""" The default for all the *extra* keywords is 0. - - -.. _lws: http://lammps.sandia.gov -.. _ld: Manual.html -.. _lc: Commands_all.html -- GitLab From 9a1b4a8edb9f1d19f79b0f6ab65a9ec4b1ebc9eb Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Wed, 28 Aug 2019 11:09:57 -0400 Subject: [PATCH 058/577] Add infrastructure for openmp4 compat --- cmake/CMakeLists.txt | 18 ++++++------ doc/src/Build_basics.rst | 8 ++---- src/USER-OMP/README | 8 ------ src/USER-OMP/hack_openmp_for_pgi_gcc9.sh | 12 -------- src/omp_compat.h | 35 ++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 35 deletions(-) delete mode 100755 src/USER-OMP/hack_openmp_for_pgi_gcc9.sh create mode 100644 src/omp_compat.h diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4dd079eaae..3dea0db8b0 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -229,16 +229,7 @@ pkg_depends(USER-SCAFACOS MPI) find_package(OpenMP QUIET) -# TODO: this is a temporary workaround until a better solution is found. AK 2019-05-30 -# GNU GCC 9.x uses settings incompatible with our use of 'default(none)' in OpenMP pragmas -# where we assume older GCC semantics. For the time being, we disable OpenMP by default -# for GCC 9.x and beyond. People may manually turn it on, but need to run the script -# src/USER-OMP/hack_openmp_for_pgi_gcc9.sh on all sources to make it compatible with gcc 9. -if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.99.9)) - option(BUILD_OMP "Build with OpenMP support" OFF) -else() - option(BUILD_OMP "Build with OpenMP support" ${OpenMP_FOUND}) -endif() +option(BUILD_OMP "Build with OpenMP support" ${OpenMP_FOUND}) if(BUILD_OMP) find_package(OpenMP REQUIRED) @@ -248,6 +239,13 @@ if(BUILD_OMP) endif() set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + + if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.99.9)) + # GCC 9.x strictly implements OpenMP 4.0 semantics for consts. + add_definitions(-DLMP_OMP_COMPAT=4) + else() + add_definitions(-DLMP_OMP_COMPAT=3) + endif() endif() if(PKG_MSCG OR PKG_USER-ATC OR PKG_USER-AWPMD OR PKG_USER-QUIP OR PKG_LATTE) diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 8ad48b0810..96bc0f5bd1 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -145,11 +145,9 @@ Some compilers do not fully support the ``default(none)`` directive and others (e.g. GCC version 9 and beyond) may implement OpenMP 4.0 semantics, which are incompatible with the OpenMP 3.1 semantics used in LAMMPS (for maximal compatibility with compiler versions in use). -In those case, all ``default(none)`` directives (which aid in detecting -incorrect and unwanted sharing) can be replaced with ``default(shared)`` -while dropping all ``shared()`` directives. The script -'src/USER-OMP/hack_openmp_for_pgi_gcc9.sh' can be used to automate -this conversion. +LAMMPS will try to detect compilers that use OpenMP 4.0 semantics and +change the directives accordingly, but if your compiler is not +detected, you may set the CMake variable ``-D LMP_OMP_COMPAT=4``. ---------- diff --git a/src/USER-OMP/README b/src/USER-OMP/README index 46f63f646b..0aef853bca 100644 --- a/src/USER-OMP/README +++ b/src/USER-OMP/README @@ -9,11 +9,3 @@ doc/Section_accelerate.html, sub-section 5.2 The person who created this package is Axel Kohlmeyer at Temple U (akohlmey at gmail.com). Contact him directly if you have questions. --------------------------- - -This directory also contains a shell script: - -hack_openmp_for_pgi.sh - -which will convert OpenMP directives in src files -into a form compatible with the PGI compiler. diff --git a/src/USER-OMP/hack_openmp_for_pgi_gcc9.sh b/src/USER-OMP/hack_openmp_for_pgi_gcc9.sh deleted file mode 100755 index 6f9f30cedd..0000000000 --- a/src/USER-OMP/hack_openmp_for_pgi_gcc9.sh +++ /dev/null @@ -1,12 +0,0 @@ -#!/bin/sh - -# convert default(none) directives for OpenMP pragmas to default(shared) and remove shared() directive -# this allows compiling OpenMP pragmas in LAMMPS with compilers that don't support default(none) properly -# or require backward incompatible OpenMP 4 and OpenMP 5 semantics - -for f in *.h *.cpp -do \ - sed -e '/#pragma omp/s/^\(.*default\)(none)\(.*\)$/\1(shared)\2/' \ - -e '/#pragma omp/s/shared([a-z0-9,_]\+)//' \ - -i.bak $f -done diff --git a/src/omp_compat.h b/src/omp_compat.h new file mode 100644 index 0000000000..8abf1c54bc --- /dev/null +++ b/src/omp_compat.h @@ -0,0 +1,35 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + http://lammps.sandia.gov, Sandia National Laboratories + Steve Plimpton, sjplimp@sandia.gov + + Copyright (2020) 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. +------------------------------------------------------------------------- */ + +// There is no way to annotate an OpenMP construct that +// (a) accesses const variables, (b) has default(none), +// and (c) is valid in both OpenMP 3.0 and 4.0. +// +// (in OpenMP 3.0, the const variables have a predetermined +// sharing attribute and are *forbidden* from being declared +// in the omp construct. In OpenMP 4.0, this predetermined +// sharing attribute is removed, and thus they are *required* +// to be declared in the omp construct) +// +// To date, most compilers still accept the OpenMP 3.0 form, +// so this is what LAMMPS primarily uses. For those compilers +// that strictly implement OpenMP 4.0 (such as GCC 9.0), we +// give up default(none). +#if LMP_OMP_COMPAT == 4 +# define LMP_SHARED(...) +# define LMP_DEFAULT_NONE default(shared) +#else +# define LMP_SHARED(...) shared(__VA_ARGS__) +# define LMP_DEFAULT_NONE default(none) +#endif + -- GitLab From 0bedebc083d326a4a8c32554dc46c98d2c379016 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Fri, 20 Mar 2020 12:16:22 -0400 Subject: [PATCH 059/577] migrate omp constructs to new macros These changes were automatically generated using the script posted in https://github.com/lammps/lammps/pull/1651#issuecomment-525814475 --- src/MPIIO/dump_atom_mpiio.cpp | 5 ++- src/MPIIO/dump_cfg_mpiio.cpp | 3 +- src/MPIIO/dump_custom_mpiio.cpp | 3 +- src/MPIIO/dump_xyz_mpiio.cpp | 3 +- src/USER-DIFFRACTION/compute_saed.cpp | 3 +- src/USER-DIFFRACTION/compute_xrd.cpp | 3 +- src/USER-INTEL/angle_charmm_intel.cpp | 3 +- src/USER-INTEL/angle_harmonic_intel.cpp | 3 +- src/USER-INTEL/bond_fene_intel.cpp | 3 +- src/USER-INTEL/bond_harmonic_intel.cpp | 3 +- src/USER-INTEL/dihedral_charmm_intel.cpp | 5 ++- src/USER-INTEL/dihedral_fourier_intel.cpp | 3 +- src/USER-INTEL/dihedral_harmonic_intel.cpp | 3 +- src/USER-INTEL/dihedral_opls_intel.cpp | 3 +- src/USER-INTEL/fix_intel.cpp | 3 +- src/USER-INTEL/improper_cvff_intel.cpp | 3 +- src/USER-INTEL/improper_harmonic_intel.cpp | 3 +- src/USER-INTEL/npair_intel.cpp | 3 +- src/USER-INTEL/pppm_disp_intel.cpp | 31 ++++++++-------- src/USER-INTEL/pppm_intel.cpp | 11 +++--- src/USER-OMP/angle_charmm_omp.cpp | 3 +- src/USER-OMP/angle_class2_omp.cpp | 3 +- src/USER-OMP/angle_cosine_delta_omp.cpp | 3 +- src/USER-OMP/angle_cosine_omp.cpp | 3 +- src/USER-OMP/angle_cosine_periodic_omp.cpp | 3 +- src/USER-OMP/angle_cosine_shift_exp_omp.cpp | 3 +- src/USER-OMP/angle_cosine_shift_omp.cpp | 3 +- src/USER-OMP/angle_cosine_squared_omp.cpp | 3 +- src/USER-OMP/angle_dipole_omp.cpp | 3 +- src/USER-OMP/angle_fourier_omp.cpp | 3 +- src/USER-OMP/angle_fourier_simple_omp.cpp | 3 +- src/USER-OMP/angle_harmonic_omp.cpp | 3 +- src/USER-OMP/angle_quartic_omp.cpp | 3 +- src/USER-OMP/angle_sdk_omp.cpp | 3 +- src/USER-OMP/angle_table_omp.cpp | 3 +- src/USER-OMP/bond_class2_omp.cpp | 3 +- src/USER-OMP/bond_fene_expand_omp.cpp | 3 +- src/USER-OMP/bond_fene_omp.cpp | 3 +- src/USER-OMP/bond_gromos_omp.cpp | 3 +- src/USER-OMP/bond_harmonic_omp.cpp | 3 +- src/USER-OMP/bond_harmonic_shift_cut_omp.cpp | 3 +- src/USER-OMP/bond_harmonic_shift_omp.cpp | 3 +- src/USER-OMP/bond_morse_omp.cpp | 3 +- src/USER-OMP/bond_nonlinear_omp.cpp | 3 +- src/USER-OMP/bond_quartic_omp.cpp | 3 +- src/USER-OMP/bond_table_omp.cpp | 3 +- src/USER-OMP/dihedral_charmm_omp.cpp | 3 +- src/USER-OMP/dihedral_class2_omp.cpp | 3 +- .../dihedral_cosine_shift_exp_omp.cpp | 3 +- src/USER-OMP/dihedral_fourier_omp.cpp | 3 +- src/USER-OMP/dihedral_harmonic_omp.cpp | 3 +- src/USER-OMP/dihedral_helix_omp.cpp | 3 +- src/USER-OMP/dihedral_multi_harmonic_omp.cpp | 3 +- src/USER-OMP/dihedral_nharmonic_omp.cpp | 3 +- src/USER-OMP/dihedral_opls_omp.cpp | 3 +- src/USER-OMP/dihedral_quadratic_omp.cpp | 3 +- src/USER-OMP/dihedral_table_omp.cpp | 3 +- src/USER-OMP/domain_omp.cpp | 7 ++-- src/USER-OMP/ewald_omp.cpp | 5 ++- src/USER-OMP/fix_gravity_omp.cpp | 5 ++- src/USER-OMP/fix_neigh_history_omp.cpp | 9 +++-- src/USER-OMP/fix_nh_asphere_omp.cpp | 9 +++-- src/USER-OMP/fix_nh_omp.cpp | 19 +++++----- src/USER-OMP/fix_nh_sphere_omp.cpp | 7 ++-- src/USER-OMP/fix_nve_omp.cpp | 9 +++-- src/USER-OMP/fix_nve_sphere_omp.cpp | 9 +++-- src/USER-OMP/fix_nvt_sllod_omp.cpp | 3 +- src/USER-OMP/fix_omp.cpp | 9 +++-- src/USER-OMP/fix_rigid_nh_omp.cpp | 23 ++++++------ src/USER-OMP/fix_rigid_omp.cpp | 19 +++++----- src/USER-OMP/fix_rigid_small_omp.cpp | 17 +++++---- src/USER-OMP/improper_class2_omp.cpp | 3 +- src/USER-OMP/improper_cossq_omp.cpp | 3 +- src/USER-OMP/improper_cvff_omp.cpp | 3 +- src/USER-OMP/improper_fourier_omp.cpp | 3 +- src/USER-OMP/improper_harmonic_omp.cpp | 3 +- src/USER-OMP/improper_ring_omp.cpp | 3 +- src/USER-OMP/improper_umbrella_omp.cpp | 3 +- src/USER-OMP/msm_cg_omp.cpp | 3 +- src/USER-OMP/msm_omp.cpp | 5 ++- src/USER-OMP/npair_full_bin_atomonly_omp.cpp | 3 +- src/USER-OMP/npair_full_bin_ghost_omp.cpp | 3 +- src/USER-OMP/npair_full_bin_omp.cpp | 3 +- src/USER-OMP/npair_full_multi_omp.cpp | 3 +- src/USER-OMP/npair_full_nsq_ghost_omp.cpp | 3 +- src/USER-OMP/npair_full_nsq_omp.cpp | 3 +- .../npair_half_bin_atomonly_newton_omp.cpp | 3 +- .../npair_half_bin_newtoff_ghost_omp.cpp | 3 +- src/USER-OMP/npair_half_bin_newtoff_omp.cpp | 3 +- src/USER-OMP/npair_half_bin_newton_omp.cpp | 3 +- .../npair_half_bin_newton_tri_omp.cpp | 3 +- src/USER-OMP/npair_half_multi_newtoff_omp.cpp | 3 +- src/USER-OMP/npair_half_multi_newton_omp.cpp | 3 +- .../npair_half_multi_newton_tri_omp.cpp | 3 +- .../npair_half_nsq_newtoff_ghost_omp.cpp | 3 +- src/USER-OMP/npair_half_nsq_newtoff_omp.cpp | 3 +- src/USER-OMP/npair_half_nsq_newton_omp.cpp | 3 +- .../npair_half_respa_bin_newtoff_omp.cpp | 3 +- .../npair_half_respa_bin_newton_omp.cpp | 3 +- .../npair_half_respa_bin_newton_tri_omp.cpp | 3 +- .../npair_half_respa_nsq_newtoff_omp.cpp | 3 +- .../npair_half_respa_nsq_newton_omp.cpp | 3 +- .../npair_half_size_bin_newtoff_omp.cpp | 3 +- .../npair_half_size_bin_newton_omp.cpp | 3 +- .../npair_half_size_bin_newton_tri_omp.cpp | 3 +- .../npair_half_size_nsq_newtoff_omp.cpp | 3 +- .../npair_half_size_nsq_newton_omp.cpp | 3 +- src/USER-OMP/npair_halffull_newtoff_omp.cpp | 3 +- src/USER-OMP/npair_halffull_newton_omp.cpp | 3 +- src/USER-OMP/pair_adp_omp.cpp | 3 +- src/USER-OMP/pair_agni_omp.cpp | 3 +- src/USER-OMP/pair_airebo_omp.cpp | 5 ++- src/USER-OMP/pair_beck_omp.cpp | 3 +- src/USER-OMP/pair_born_coul_long_omp.cpp | 3 +- src/USER-OMP/pair_born_coul_msm_omp.cpp | 3 +- src/USER-OMP/pair_born_coul_wolf_omp.cpp | 3 +- src/USER-OMP/pair_born_omp.cpp | 3 +- src/USER-OMP/pair_brownian_omp.cpp | 3 +- src/USER-OMP/pair_brownian_poly_omp.cpp | 3 +- src/USER-OMP/pair_buck_coul_cut_omp.cpp | 3 +- src/USER-OMP/pair_buck_coul_long_omp.cpp | 3 +- src/USER-OMP/pair_buck_coul_msm_omp.cpp | 3 +- src/USER-OMP/pair_buck_long_coul_long_omp.cpp | 9 +++-- src/USER-OMP/pair_buck_omp.cpp | 3 +- src/USER-OMP/pair_colloid_omp.cpp | 3 +- src/USER-OMP/pair_comb_omp.cpp | 7 ++-- src/USER-OMP/pair_coul_cut_omp.cpp | 3 +- src/USER-OMP/pair_coul_cut_soft_omp.cpp | 3 +- src/USER-OMP/pair_coul_debye_omp.cpp | 3 +- src/USER-OMP/pair_coul_diel_omp.cpp | 3 +- src/USER-OMP/pair_coul_dsf_omp.cpp | 3 +- src/USER-OMP/pair_coul_long_omp.cpp | 3 +- src/USER-OMP/pair_coul_long_soft_omp.cpp | 3 +- src/USER-OMP/pair_coul_msm_omp.cpp | 3 +- src/USER-OMP/pair_coul_wolf_omp.cpp | 3 +- src/USER-OMP/pair_dpd_omp.cpp | 3 +- src/USER-OMP/pair_dpd_tstat_omp.cpp | 3 +- src/USER-OMP/pair_eam_cd_omp.cpp | 3 +- src/USER-OMP/pair_eam_omp.cpp | 3 +- src/USER-OMP/pair_edip_omp.cpp | 3 +- src/USER-OMP/pair_eim_omp.cpp | 3 +- src/USER-OMP/pair_gauss_cut_omp.cpp | 3 +- src/USER-OMP/pair_gauss_omp.cpp | 3 +- src/USER-OMP/pair_gayberne_omp.cpp | 3 +- src/USER-OMP/pair_gran_hertz_history_omp.cpp | 3 +- src/USER-OMP/pair_gran_hooke_history_omp.cpp | 3 +- src/USER-OMP/pair_gran_hooke_omp.cpp | 3 +- src/USER-OMP/pair_hbond_dreiding_lj_omp.cpp | 3 +- .../pair_hbond_dreiding_morse_omp.cpp | 3 +- src/USER-OMP/pair_lj96_cut_omp.cpp | 3 +- ...air_lj_charmm_coul_charmm_implicit_omp.cpp | 3 +- .../pair_lj_charmm_coul_charmm_omp.cpp | 3 +- src/USER-OMP/pair_lj_charmm_coul_long_omp.cpp | 3 +- .../pair_lj_charmm_coul_long_soft_omp.cpp | 3 +- src/USER-OMP/pair_lj_charmm_coul_msm_omp.cpp | 3 +- src/USER-OMP/pair_lj_class2_coul_cut_omp.cpp | 3 +- src/USER-OMP/pair_lj_class2_coul_long_omp.cpp | 3 +- src/USER-OMP/pair_lj_class2_omp.cpp | 3 +- src/USER-OMP/pair_lj_cubic_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_coul_cut_omp.cpp | 3 +- .../pair_lj_cut_coul_cut_soft_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_coul_debye_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_coul_dsf_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_coul_long_omp.cpp | 3 +- .../pair_lj_cut_coul_long_soft_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_coul_msm_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_coul_wolf_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_dipole_cut_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_soft_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_thole_long_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_tip4p_cut_omp.cpp | 3 +- src/USER-OMP/pair_lj_cut_tip4p_long_omp.cpp | 3 +- .../pair_lj_cut_tip4p_long_soft_omp.cpp | 3 +- src/USER-OMP/pair_lj_expand_omp.cpp | 3 +- .../pair_lj_gromacs_coul_gromacs_omp.cpp | 3 +- src/USER-OMP/pair_lj_gromacs_omp.cpp | 3 +- src/USER-OMP/pair_lj_long_coul_long_omp.cpp | 9 +++-- src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp | 9 +++-- src/USER-OMP/pair_lj_sdk_coul_long_omp.cpp | 3 +- src/USER-OMP/pair_lj_sdk_coul_msm_omp.cpp | 3 +- src/USER-OMP/pair_lj_sdk_omp.cpp | 3 +- src/USER-OMP/pair_lj_sf_dipole_sf_omp.cpp | 3 +- src/USER-OMP/pair_lj_smooth_linear_omp.cpp | 3 +- src/USER-OMP/pair_lj_smooth_omp.cpp | 3 +- src/USER-OMP/pair_lubricate_omp.cpp | 3 +- src/USER-OMP/pair_lubricate_poly_omp.cpp | 3 +- src/USER-OMP/pair_meam_spline_omp.cpp | 3 +- src/USER-OMP/pair_morse_omp.cpp | 3 +- src/USER-OMP/pair_morse_smooth_linear_omp.cpp | 3 +- src/USER-OMP/pair_nm_cut_coul_cut_omp.cpp | 3 +- src/USER-OMP/pair_nm_cut_coul_long_omp.cpp | 3 +- src/USER-OMP/pair_nm_cut_omp.cpp | 3 +- src/USER-OMP/pair_peri_lps_omp.cpp | 3 +- src/USER-OMP/pair_peri_pmb_omp.cpp | 3 +- src/USER-OMP/pair_resquared_omp.cpp | 3 +- src/USER-OMP/pair_soft_omp.cpp | 3 +- src/USER-OMP/pair_sw_omp.cpp | 3 +- src/USER-OMP/pair_table_omp.cpp | 3 +- src/USER-OMP/pair_tersoff_mod_c_omp.cpp | 3 +- src/USER-OMP/pair_tersoff_mod_omp.cpp | 3 +- src/USER-OMP/pair_tersoff_omp.cpp | 3 +- src/USER-OMP/pair_tersoff_table_omp.cpp | 3 +- src/USER-OMP/pair_tip4p_cut_omp.cpp | 3 +- src/USER-OMP/pair_tip4p_long_omp.cpp | 3 +- src/USER-OMP/pair_tip4p_long_soft_omp.cpp | 3 +- src/USER-OMP/pair_ufm_omp.cpp | 3 +- src/USER-OMP/pair_vashishta_omp.cpp | 3 +- src/USER-OMP/pair_vashishta_table_omp.cpp | 3 +- src/USER-OMP/pair_yukawa_colloid_omp.cpp | 3 +- src/USER-OMP/pair_yukawa_omp.cpp | 3 +- src/USER-OMP/pair_zbl_omp.cpp | 3 +- src/USER-OMP/pppm_cg_omp.cpp | 19 +++++----- src/USER-OMP/pppm_disp_omp.cpp | 37 ++++++++++--------- src/USER-OMP/pppm_disp_tip4p_omp.cpp | 37 ++++++++++--------- src/USER-OMP/pppm_omp.cpp | 19 +++++----- src/USER-OMP/pppm_tip4p_omp.cpp | 19 +++++----- src/USER-OMP/reaxc_forces_omp.cpp | 3 +- src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp | 3 +- src/USER-OMP/respa_omp.cpp | 7 ++-- 220 files changed, 587 insertions(+), 367 deletions(-) diff --git a/src/MPIIO/dump_atom_mpiio.cpp b/src/MPIIO/dump_atom_mpiio.cpp index 2b663554cc..d59ed7bde8 100644 --- a/src/MPIIO/dump_atom_mpiio.cpp +++ b/src/MPIIO/dump_atom_mpiio.cpp @@ -15,6 +15,7 @@ Contributing author: Paul Coffman (IBM) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dump_atom_mpiio.h" #include #include @@ -587,7 +588,7 @@ int DumpAtomMPIIO::convert_image_omp(int n, double *mybuf) mpifh_buffer_line_per_thread[i] = (char *) malloc(DUMP_BUF_CHUNK_SIZE * sizeof(char)); mpifh_buffer_line_per_thread[i][0] = '\0'; -#pragma omp parallel default(none) shared(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) { int tid = omp_get_thread_num(); int m=0; @@ -677,7 +678,7 @@ int DumpAtomMPIIO::convert_noimage_omp(int n, double *mybuf) mpifh_buffer_line_per_thread[i] = (char *) malloc(DUMP_BUF_CHUNK_SIZE * sizeof(char)); mpifh_buffer_line_per_thread[i][0] = '\0'; -#pragma omp parallel default(none) shared(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) { int tid = omp_get_thread_num(); int m=0; diff --git a/src/MPIIO/dump_cfg_mpiio.cpp b/src/MPIIO/dump_cfg_mpiio.cpp index 31848b550c..18368db330 100644 --- a/src/MPIIO/dump_cfg_mpiio.cpp +++ b/src/MPIIO/dump_cfg_mpiio.cpp @@ -15,6 +15,7 @@ Contributing author: Paul Coffman (IBM) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dump_cfg_mpiio.h" #include #include @@ -365,7 +366,7 @@ int DumpCFGMPIIO::convert_string_omp(int n, double *mybuf) mpifh_buffer_line_per_thread[i] = (char *) malloc(DUMP_BUF_CHUNK_SIZE * sizeof(char)); mpifh_buffer_line_per_thread[i][0] = '\0'; -#pragma omp parallel default(none) shared(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) { int tid = omp_get_thread_num(); int m=0; diff --git a/src/MPIIO/dump_custom_mpiio.cpp b/src/MPIIO/dump_custom_mpiio.cpp index dca5833c5b..526021d895 100644 --- a/src/MPIIO/dump_custom_mpiio.cpp +++ b/src/MPIIO/dump_custom_mpiio.cpp @@ -15,6 +15,7 @@ Contributing author: Paul Coffman (IBM) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dump_custom_mpiio.h" #include #include @@ -612,7 +613,7 @@ int DumpCustomMPIIO::convert_string_omp(int n, double *mybuf) mpifh_buffer_line_per_thread[i] = (char *) malloc(DUMP_BUF_CHUNK_SIZE * sizeof(char)); mpifh_buffer_line_per_thread[i][0] = '\0'; -#pragma omp parallel default(none) shared(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) { int tid = omp_get_thread_num(); int m=0; diff --git a/src/MPIIO/dump_xyz_mpiio.cpp b/src/MPIIO/dump_xyz_mpiio.cpp index f5caab3a9c..a1e4f21a79 100644 --- a/src/MPIIO/dump_xyz_mpiio.cpp +++ b/src/MPIIO/dump_xyz_mpiio.cpp @@ -15,6 +15,7 @@ Contributing author: Paul Coffman (IBM) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dump_xyz_mpiio.h" #include #include @@ -350,7 +351,7 @@ int DumpXYZMPIIO::convert_string_omp(int n, double *mybuf) mpifh_buffer_line_per_thread[i] = (char *) malloc(DUMP_BUF_CHUNK_SIZE * sizeof(char)); mpifh_buffer_line_per_thread[i][0] = '\0'; -#pragma omp parallel default(none) shared(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(bufOffset, bufRange, bufLength, mpifhStringCountPerThread, mpifh_buffer_line_per_thread, mybuf) { int tid = omp_get_thread_num(); int m=0; diff --git a/src/USER-DIFFRACTION/compute_saed.cpp b/src/USER-DIFFRACTION/compute_saed.cpp index 7b5b2f4f5b..5dd47b28bd 100644 --- a/src/USER-DIFFRACTION/compute_saed.cpp +++ b/src/USER-DIFFRACTION/compute_saed.cpp @@ -15,6 +15,7 @@ Contributing authors: Shawn Coleman & Douglas Spearot (Arkansas) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "compute_saed.h" #include #include @@ -418,7 +419,7 @@ void ComputeSAED::compute_vector() double frac = 0.1; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(offset,ASFSAED,typelocal,xlocal,Fvec,m,frac) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(offset,ASFSAED,typelocal,xlocal,Fvec,m,frac) #endif { double *f = new double[ntypes]; // atomic structure factor by type diff --git a/src/USER-DIFFRACTION/compute_xrd.cpp b/src/USER-DIFFRACTION/compute_xrd.cpp index 7f69449282..e75546b548 100644 --- a/src/USER-DIFFRACTION/compute_xrd.cpp +++ b/src/USER-DIFFRACTION/compute_xrd.cpp @@ -16,6 +16,7 @@ Updated: 06/17/2015-2 ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "compute_xrd.h" #include #include @@ -353,7 +354,7 @@ void ComputeXRD::compute_array() double frac = 0.1; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(typelocal,xlocal,Fvec,m,frac,ASFXRD) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(typelocal,xlocal,Fvec,m,frac,ASFXRD) #endif { double *f = new double[ntypes]; // atomic structure factor by type diff --git a/src/USER-INTEL/angle_charmm_intel.cpp b/src/USER-INTEL/angle_charmm_intel.cpp index 43de50e7fa..9275e82f1c 100644 --- a/src/USER-INTEL/angle_charmm_intel.cpp +++ b/src/USER-INTEL/angle_charmm_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "angle_charmm_intel.h" @@ -134,7 +135,7 @@ void AngleCharmmIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oeangle,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/angle_harmonic_intel.cpp b/src/USER-INTEL/angle_harmonic_intel.cpp index d073e7bc56..49a71038da 100644 --- a/src/USER-INTEL/angle_harmonic_intel.cpp +++ b/src/USER-INTEL/angle_harmonic_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "angle_harmonic_intel.h" @@ -134,7 +135,7 @@ void AngleHarmonicIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oeangle,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/bond_fene_intel.cpp b/src/USER-INTEL/bond_fene_intel.cpp index 6578706a9b..5c58e7bf10 100644 --- a/src/USER-INTEL/bond_fene_intel.cpp +++ b/src/USER-INTEL/bond_fene_intel.cpp @@ -15,6 +15,7 @@ Contributing author: Stan Moore (Sandia) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "bond_fene_intel.h" @@ -127,7 +128,7 @@ void BondFENEIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oebond,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/bond_harmonic_intel.cpp b/src/USER-INTEL/bond_harmonic_intel.cpp index 55dda9fa15..8bf0a82218 100644 --- a/src/USER-INTEL/bond_harmonic_intel.cpp +++ b/src/USER-INTEL/bond_harmonic_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "bond_harmonic_intel.h" @@ -127,7 +128,7 @@ void BondHarmonicIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oebond,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/dihedral_charmm_intel.cpp b/src/USER-INTEL/dihedral_charmm_intel.cpp index 2ea4eb6d21..61fc1dfbd5 100644 --- a/src/USER-INTEL/dihedral_charmm_intel.cpp +++ b/src/USER-INTEL/dihedral_charmm_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "dihedral_charmm_intel.h" @@ -148,7 +149,7 @@ void DihedralCharmmIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oevdwl,oecoul,oedihedral,ov0,ov1,ov2,ov3,ov4,ov5, \ opv0,opv1,opv2,opv3,opv4,opv5) @@ -522,7 +523,7 @@ void DihedralCharmmIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oevdwl,oecoul,oedihedral,ov0,ov1,ov2,ov3,ov4,ov5, \ opv0,opv1,opv2,opv3,opv4,opv5) diff --git a/src/USER-INTEL/dihedral_fourier_intel.cpp b/src/USER-INTEL/dihedral_fourier_intel.cpp index 8c4a2ce921..fb8051474e 100644 --- a/src/USER-INTEL/dihedral_fourier_intel.cpp +++ b/src/USER-INTEL/dihedral_fourier_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "dihedral_fourier_intel.h" @@ -127,7 +128,7 @@ void DihedralFourierIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oedihedral,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/dihedral_harmonic_intel.cpp b/src/USER-INTEL/dihedral_harmonic_intel.cpp index 60655f2618..f6c4ea0fde 100644 --- a/src/USER-INTEL/dihedral_harmonic_intel.cpp +++ b/src/USER-INTEL/dihedral_harmonic_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "dihedral_harmonic_intel.h" @@ -127,7 +128,7 @@ void DihedralHarmonicIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oedihedral,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/dihedral_opls_intel.cpp b/src/USER-INTEL/dihedral_opls_intel.cpp index 5b580cd7d9..79a8874a72 100644 --- a/src/USER-INTEL/dihedral_opls_intel.cpp +++ b/src/USER-INTEL/dihedral_opls_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "dihedral_opls_intel.h" @@ -131,7 +132,7 @@ void DihedralOPLSIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oedihedral,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/fix_intel.cpp b/src/USER-INTEL/fix_intel.cpp index 5ecae79b30..c62a6a432a 100644 --- a/src/USER-INTEL/fix_intel.cpp +++ b/src/USER-INTEL/fix_intel.cpp @@ -16,6 +16,7 @@ Anupama Kurpad (Intel) - Host Affinitization ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_intel.h" #include "comm.h" #include "error.h" @@ -220,7 +221,7 @@ FixIntel::FixIntel(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg) comm->nthreads = nomp; } else { int nthreads; - #pragma omp parallel default(none) shared(nthreads) + #pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(nthreads) nthreads = omp_get_num_threads(); comm->nthreads = nthreads; } diff --git a/src/USER-INTEL/improper_cvff_intel.cpp b/src/USER-INTEL/improper_cvff_intel.cpp index f198e47d5c..4562c63cdb 100644 --- a/src/USER-INTEL/improper_cvff_intel.cpp +++ b/src/USER-INTEL/improper_cvff_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include @@ -138,7 +139,7 @@ void ImproperCvffIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oeimproper,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/improper_harmonic_intel.cpp b/src/USER-INTEL/improper_harmonic_intel.cpp index d638e6a66e..fc5cf08c52 100644 --- a/src/USER-INTEL/improper_harmonic_intel.cpp +++ b/src/USER-INTEL/improper_harmonic_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include @@ -139,7 +140,7 @@ void ImproperHarmonicIntel::eval(const int vflag, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(f_start,f_stride,fc) \ reduction(+:oeimproper,ov0,ov1,ov2,ov3,ov4,ov5) #endif diff --git a/src/USER-INTEL/npair_intel.cpp b/src/USER-INTEL/npair_intel.cpp index 4256e03b3c..f7a233efc9 100644 --- a/src/USER-INTEL/npair_intel.cpp +++ b/src/USER-INTEL/npair_intel.cpp @@ -15,6 +15,7 @@ Contributing author: W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "comm.h" #include "domain.h" #include "timer.h" @@ -263,7 +264,7 @@ void NPairIntel::bin_newton(const int offload, NeighList *list, } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(overflow, nstencilp, binstart, binend) #endif { diff --git a/src/USER-INTEL/pppm_disp_intel.cpp b/src/USER-INTEL/pppm_disp_intel.cpp index fd1302da98..75fdc3b1df 100644 --- a/src/USER-INTEL/pppm_disp_intel.cpp +++ b/src/USER-INTEL/pppm_disp_intel.cpp @@ -15,6 +15,7 @@ Contributing authors: William McDoniel (RWTH Aachen University) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include @@ -729,7 +730,7 @@ void PPPMDispIntel::particle_map(double delx, double dely, double delz, int flag = 0; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr, delx, dely, delz, sft, p2g, nup, nlow, nxlo,\ nylo, nzlo, nxhi, nyhi, nzhi) reduction(+:flag) if(!_use_lrt) #endif @@ -803,7 +804,7 @@ void PPPMDispIntel::make_rho_c(IntelBuffers * /*buffers*/) int nthr = comm->nthreads; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, nlocal, global_density) if(!_use_lrt) #endif { @@ -909,7 +910,7 @@ void PPPMDispIntel::make_rho_c(IntelBuffers * /*buffers*/) // reduce all the perthread_densities into global_density #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, global_density) if(!_use_lrt) #endif { @@ -951,7 +952,7 @@ void PPPMDispIntel::make_rho_g(IntelBuffers * /*buffers*/) int nthr = comm->nthreads; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, nlocal, global_density) if(!_use_lrt) #endif { @@ -1059,7 +1060,7 @@ void PPPMDispIntel::make_rho_g(IntelBuffers * /*buffers*/) // reduce all the perthread_densities into global_density #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, global_density) if(!_use_lrt) #endif { @@ -1234,7 +1235,7 @@ void PPPMDispIntel::make_rho_none(IntelBuffers * /*buffers*/) int nthr = comm->nthreads; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, nlocal, global_density) if(!_use_lrt) #endif { @@ -1343,7 +1344,7 @@ void PPPMDispIntel::make_rho_none(IntelBuffers * /*buffers*/) // reduce all the perthread_densities into global_density #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, global_density) if(!_use_lrt) #endif { @@ -1386,7 +1387,7 @@ void PPPMDispIntel::fieldforce_c_ik(IntelBuffers * /*buffers*/) #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -1536,7 +1537,7 @@ void PPPMDispIntel::fieldforce_c_ad(IntelBuffers * /*buffers*/) FFT_SCALAR * _noalias const particle_ekz = this->particle_ekz; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -1734,7 +1735,7 @@ void PPPMDispIntel::fieldforce_g_ik(IntelBuffers * /*buffers*/) #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -1881,7 +1882,7 @@ void PPPMDispIntel::fieldforce_g_ad(IntelBuffers * /*buffers*/) FFT_SCALAR * _noalias const particle_ekz = this->particle_ekz; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -2078,7 +2079,7 @@ void PPPMDispIntel::fieldforce_a_ik(IntelBuffers * /*buffers*/) #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -2312,7 +2313,7 @@ void PPPMDispIntel::fieldforce_a_ad(IntelBuffers * /*buffers*/) FFT_SCALAR * _noalias const particle_ekz6 = this->particle_ekz6; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -2603,7 +2604,7 @@ void PPPMDispIntel::fieldforce_none_ik(IntelBuffers * /*buffers*/) #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -2762,7 +2763,7 @@ void PPPMDispIntel::fieldforce_none_ad(IntelBuffers * /*buffers*/) int nthr = comm->nthreads; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { diff --git a/src/USER-INTEL/pppm_intel.cpp b/src/USER-INTEL/pppm_intel.cpp index e3bf779cc1..d643da96b2 100644 --- a/src/USER-INTEL/pppm_intel.cpp +++ b/src/USER-INTEL/pppm_intel.cpp @@ -18,6 +18,7 @@ W. Michael Brown (Intel) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include @@ -372,7 +373,7 @@ void PPPMIntel::particle_map(IntelBuffers *buffers) error->one(FLERR,"Non-numeric box dimensions - simulation unstable"); #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) reduction(+:flag) if(!_use_lrt) #endif { @@ -446,7 +447,7 @@ void PPPMIntel::make_rho(IntelBuffers *buffers) nthr = comm->nthreads; #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, nlocal, global_density) if(!_use_lrt) #endif { @@ -549,7 +550,7 @@ void PPPMIntel::make_rho(IntelBuffers *buffers) // reduce all the perthread_densities into global_density if (nthr > 1) { #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nthr, global_density) if(!_use_lrt) #endif { @@ -598,7 +599,7 @@ void PPPMIntel::fieldforce_ik(IntelBuffers *buffers) } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { @@ -749,7 +750,7 @@ void PPPMIntel::fieldforce_ad(IntelBuffers *buffers) } #if defined(_OPENMP) - #pragma omp parallel default(none) \ + #pragma omp parallel LMP_DEFAULT_NONE \ shared(nlocal, nthr) if(!_use_lrt) #endif { diff --git a/src/USER-OMP/angle_charmm_omp.cpp b/src/USER-OMP/angle_charmm_omp.cpp index 116c937788..6933afdcd9 100644 --- a/src/USER-OMP/angle_charmm_omp.cpp +++ b/src/USER-OMP/angle_charmm_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_charmm_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleCharmmOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_class2_omp.cpp b/src/USER-OMP/angle_class2_omp.cpp index 9aab1d73b3..09ee59d5af 100644 --- a/src/USER-OMP/angle_class2_omp.cpp +++ b/src/USER-OMP/angle_class2_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_class2_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleClass2OMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_cosine_delta_omp.cpp b/src/USER-OMP/angle_cosine_delta_omp.cpp index 44326c124e..ca5afe1449 100644 --- a/src/USER-OMP/angle_cosine_delta_omp.cpp +++ b/src/USER-OMP/angle_cosine_delta_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_cosine_delta_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleCosineDeltaOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_cosine_omp.cpp b/src/USER-OMP/angle_cosine_omp.cpp index 3bfa2aa39c..48fdd9ba60 100644 --- a/src/USER-OMP/angle_cosine_omp.cpp +++ b/src/USER-OMP/angle_cosine_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_cosine_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleCosineOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_cosine_periodic_omp.cpp b/src/USER-OMP/angle_cosine_periodic_omp.cpp index 700179119c..a0e45fe131 100644 --- a/src/USER-OMP/angle_cosine_periodic_omp.cpp +++ b/src/USER-OMP/angle_cosine_periodic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_cosine_periodic_omp.h" #include #include "atom.h" @@ -49,7 +50,7 @@ void AngleCosinePeriodicOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_cosine_shift_exp_omp.cpp b/src/USER-OMP/angle_cosine_shift_exp_omp.cpp index 1e37688425..21019336b3 100644 --- a/src/USER-OMP/angle_cosine_shift_exp_omp.cpp +++ b/src/USER-OMP/angle_cosine_shift_exp_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_cosine_shift_exp_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleCosineShiftExpOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_cosine_shift_omp.cpp b/src/USER-OMP/angle_cosine_shift_omp.cpp index 35b409edf1..1e6d712b62 100644 --- a/src/USER-OMP/angle_cosine_shift_omp.cpp +++ b/src/USER-OMP/angle_cosine_shift_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_cosine_shift_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleCosineShiftOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_cosine_squared_omp.cpp b/src/USER-OMP/angle_cosine_squared_omp.cpp index 9da5a0fce3..6df1e028a0 100644 --- a/src/USER-OMP/angle_cosine_squared_omp.cpp +++ b/src/USER-OMP/angle_cosine_squared_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_cosine_squared_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleCosineSquaredOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_dipole_omp.cpp b/src/USER-OMP/angle_dipole_omp.cpp index 33ec216f6a..26d8a7817e 100644 --- a/src/USER-OMP/angle_dipole_omp.cpp +++ b/src/USER-OMP/angle_dipole_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_dipole_omp.h" #include #include "atom.h" @@ -51,7 +52,7 @@ void AngleDipoleOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_fourier_omp.cpp b/src/USER-OMP/angle_fourier_omp.cpp index 64ff99e6c6..b6ddea3ff9 100644 --- a/src/USER-OMP/angle_fourier_omp.cpp +++ b/src/USER-OMP/angle_fourier_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_fourier_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleFourierOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_fourier_simple_omp.cpp b/src/USER-OMP/angle_fourier_simple_omp.cpp index 2ae8c5561d..992acf7c99 100644 --- a/src/USER-OMP/angle_fourier_simple_omp.cpp +++ b/src/USER-OMP/angle_fourier_simple_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_fourier_simple_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleFourierSimpleOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_harmonic_omp.cpp b/src/USER-OMP/angle_harmonic_omp.cpp index 66c0602396..0cfc6f95af 100644 --- a/src/USER-OMP/angle_harmonic_omp.cpp +++ b/src/USER-OMP/angle_harmonic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_harmonic_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleHarmonicOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_quartic_omp.cpp b/src/USER-OMP/angle_quartic_omp.cpp index 903b0e4225..a774edb8c4 100644 --- a/src/USER-OMP/angle_quartic_omp.cpp +++ b/src/USER-OMP/angle_quartic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_quartic_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleQuarticOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_sdk_omp.cpp b/src/USER-OMP/angle_sdk_omp.cpp index 3c8ee9cde8..e0bc021f1b 100644 --- a/src/USER-OMP/angle_sdk_omp.cpp +++ b/src/USER-OMP/angle_sdk_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_sdk_omp.h" #include #include "atom.h" @@ -49,7 +50,7 @@ void AngleSDKOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/angle_table_omp.cpp b/src/USER-OMP/angle_table_omp.cpp index de36d09980..1af60f85f6 100644 --- a/src/USER-OMP/angle_table_omp.cpp +++ b/src/USER-OMP/angle_table_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "angle_table_omp.h" #include #include "atom.h" @@ -47,7 +48,7 @@ void AngleTableOMP::compute(int eflag, int vflag) const int inum = neighbor->nanglelist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_class2_omp.cpp b/src/USER-OMP/bond_class2_omp.cpp index 9da50d1aa0..06edf46024 100644 --- a/src/USER-OMP/bond_class2_omp.cpp +++ b/src/USER-OMP/bond_class2_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_class2_omp.h" #include "atom.h" #include "comm.h" @@ -47,7 +48,7 @@ void BondClass2OMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_fene_expand_omp.cpp b/src/USER-OMP/bond_fene_expand_omp.cpp index a937cb6c34..5f3dd48841 100644 --- a/src/USER-OMP/bond_fene_expand_omp.cpp +++ b/src/USER-OMP/bond_fene_expand_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_fene_expand_omp.h" #include "atom.h" #include "comm.h" @@ -48,7 +49,7 @@ void BondFENEExpandOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_fene_omp.cpp b/src/USER-OMP/bond_fene_omp.cpp index 3c653fedae..ebf5afdc57 100644 --- a/src/USER-OMP/bond_fene_omp.cpp +++ b/src/USER-OMP/bond_fene_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_fene_omp.h" #include "atom.h" #include "comm.h" @@ -48,7 +49,7 @@ void BondFENEOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_gromos_omp.cpp b/src/USER-OMP/bond_gromos_omp.cpp index cedd5f96b7..e5eebfebfc 100644 --- a/src/USER-OMP/bond_gromos_omp.cpp +++ b/src/USER-OMP/bond_gromos_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_gromos_omp.h" #include "atom.h" #include "comm.h" @@ -44,7 +45,7 @@ void BondGromosOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_harmonic_omp.cpp b/src/USER-OMP/bond_harmonic_omp.cpp index 4144f02a39..9160ee7023 100644 --- a/src/USER-OMP/bond_harmonic_omp.cpp +++ b/src/USER-OMP/bond_harmonic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_harmonic_omp.h" #include "atom.h" #include "comm.h" @@ -46,7 +47,7 @@ void BondHarmonicOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_harmonic_shift_cut_omp.cpp b/src/USER-OMP/bond_harmonic_shift_cut_omp.cpp index 10e4cdcd1c..7a6c616e4a 100644 --- a/src/USER-OMP/bond_harmonic_shift_cut_omp.cpp +++ b/src/USER-OMP/bond_harmonic_shift_cut_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_harmonic_shift_cut_omp.h" #include "atom.h" #include "comm.h" @@ -46,7 +47,7 @@ void BondHarmonicShiftCutOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_harmonic_shift_omp.cpp b/src/USER-OMP/bond_harmonic_shift_omp.cpp index a0a7750890..19f0a08510 100644 --- a/src/USER-OMP/bond_harmonic_shift_omp.cpp +++ b/src/USER-OMP/bond_harmonic_shift_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_harmonic_shift_omp.h" #include "atom.h" #include "comm.h" @@ -46,7 +47,7 @@ void BondHarmonicShiftOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_morse_omp.cpp b/src/USER-OMP/bond_morse_omp.cpp index 32361cb5de..90318c8faf 100644 --- a/src/USER-OMP/bond_morse_omp.cpp +++ b/src/USER-OMP/bond_morse_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_morse_omp.h" #include "atom.h" #include "comm.h" @@ -46,7 +47,7 @@ void BondMorseOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_nonlinear_omp.cpp b/src/USER-OMP/bond_nonlinear_omp.cpp index f21772435f..809950f2b7 100644 --- a/src/USER-OMP/bond_nonlinear_omp.cpp +++ b/src/USER-OMP/bond_nonlinear_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_nonlinear_omp.h" #include "atom.h" #include "comm.h" @@ -46,7 +47,7 @@ void BondNonlinearOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_quartic_omp.cpp b/src/USER-OMP/bond_quartic_omp.cpp index 46ee4ab96b..0efaa10e37 100644 --- a/src/USER-OMP/bond_quartic_omp.cpp +++ b/src/USER-OMP/bond_quartic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_quartic_omp.h" #include "atom.h" #include "comm.h" @@ -52,7 +53,7 @@ void BondQuarticOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/bond_table_omp.cpp b/src/USER-OMP/bond_table_omp.cpp index db1599fbcc..f503bcab26 100644 --- a/src/USER-OMP/bond_table_omp.cpp +++ b/src/USER-OMP/bond_table_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "bond_table_omp.h" #include "atom.h" #include "comm.h" @@ -46,7 +47,7 @@ void BondTableOMP::compute(int eflag, int vflag) const int inum = neighbor->nbondlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_charmm_omp.cpp b/src/USER-OMP/dihedral_charmm_omp.cpp index 242a0a1d86..afd3071434 100644 --- a/src/USER-OMP/dihedral_charmm_omp.cpp +++ b/src/USER-OMP/dihedral_charmm_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dihedral_charmm_omp.h" #include #include "atom.h" @@ -56,7 +57,7 @@ void DihedralCharmmOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_class2_omp.cpp b/src/USER-OMP/dihedral_class2_omp.cpp index 215677612b..49b8659e2f 100644 --- a/src/USER-OMP/dihedral_class2_omp.cpp +++ b/src/USER-OMP/dihedral_class2_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_class2_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void DihedralClass2OMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_cosine_shift_exp_omp.cpp b/src/USER-OMP/dihedral_cosine_shift_exp_omp.cpp index f42121f8a9..cea22adf1b 100644 --- a/src/USER-OMP/dihedral_cosine_shift_exp_omp.cpp +++ b/src/USER-OMP/dihedral_cosine_shift_exp_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_cosine_shift_exp_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void DihedralCosineShiftExpOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_fourier_omp.cpp b/src/USER-OMP/dihedral_fourier_omp.cpp index cd12b3630e..756931774a 100644 --- a/src/USER-OMP/dihedral_fourier_omp.cpp +++ b/src/USER-OMP/dihedral_fourier_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dihedral_fourier_omp.h" #include #include "atom.h" @@ -49,7 +50,7 @@ void DihedralFourierOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_harmonic_omp.cpp b/src/USER-OMP/dihedral_harmonic_omp.cpp index c3adb113e2..d1f511954e 100644 --- a/src/USER-OMP/dihedral_harmonic_omp.cpp +++ b/src/USER-OMP/dihedral_harmonic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_harmonic_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void DihedralHarmonicOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_helix_omp.cpp b/src/USER-OMP/dihedral_helix_omp.cpp index b38ff2739a..5289fc2c62 100644 --- a/src/USER-OMP/dihedral_helix_omp.cpp +++ b/src/USER-OMP/dihedral_helix_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_helix_omp.h" #include "atom.h" @@ -53,7 +54,7 @@ void DihedralHelixOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_multi_harmonic_omp.cpp b/src/USER-OMP/dihedral_multi_harmonic_omp.cpp index 7b79a63722..edf8a20899 100644 --- a/src/USER-OMP/dihedral_multi_harmonic_omp.cpp +++ b/src/USER-OMP/dihedral_multi_harmonic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_multi_harmonic_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void DihedralMultiHarmonicOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_nharmonic_omp.cpp b/src/USER-OMP/dihedral_nharmonic_omp.cpp index f3d8471c95..bf51a01713 100644 --- a/src/USER-OMP/dihedral_nharmonic_omp.cpp +++ b/src/USER-OMP/dihedral_nharmonic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_nharmonic_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void DihedralNHarmonicOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_opls_omp.cpp b/src/USER-OMP/dihedral_opls_omp.cpp index 24cc4cd064..8814d3f3f0 100644 --- a/src/USER-OMP/dihedral_opls_omp.cpp +++ b/src/USER-OMP/dihedral_opls_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_opls_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void DihedralOPLSOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_quadratic_omp.cpp b/src/USER-OMP/dihedral_quadratic_omp.cpp index 6f82c1e6b0..e61c5f0d85 100644 --- a/src/USER-OMP/dihedral_quadratic_omp.cpp +++ b/src/USER-OMP/dihedral_quadratic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "dihedral_quadratic_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void DihedralQuadraticOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/dihedral_table_omp.cpp b/src/USER-OMP/dihedral_table_omp.cpp index a760fc6094..bf5332a1c1 100644 --- a/src/USER-OMP/dihedral_table_omp.cpp +++ b/src/USER-OMP/dihedral_table_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "dihedral_table_omp.h" #include #include "atom.h" @@ -113,7 +114,7 @@ void DihedralTableOMP::compute(int eflag, int vflag) const int inum = neighbor->ndihedrallist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/domain_omp.cpp b/src/USER-OMP/domain_omp.cpp index 18d2a587ca..dfd3d3590f 100644 --- a/src/USER-OMP/domain_omp.cpp +++ b/src/USER-OMP/domain_omp.cpp @@ -15,6 +15,7 @@ Contributing author : Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "accelerator_omp.h" #include "atom.h" @@ -45,7 +46,7 @@ void DomainOMP::pbc() const int nlocal = atom->nlocal; #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { imageint idim,otherdims; @@ -143,7 +144,7 @@ void DomainOMP::lamda2x(int n) const int num = n; #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < num; i++) { x[i].x = h[0]*x[i].x + h[5]*x[i].y + h[4]*x[i].z + boxlo[0]; @@ -163,7 +164,7 @@ void DomainOMP::x2lamda(int n) const int num = n; #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < num; i++) { double delta0 = x[i].x - boxlo[0]; diff --git a/src/USER-OMP/ewald_omp.cpp b/src/USER-OMP/ewald_omp.cpp index a539394f69..fd776e46a6 100644 --- a/src/USER-OMP/ewald_omp.cpp +++ b/src/USER-OMP/ewald_omp.cpp @@ -15,6 +15,7 @@ Contributing authors: Roy Pollock (LLNL), Paul Crozier (SNL) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "ewald_omp.h" #include #include @@ -104,7 +105,7 @@ void EwaldOMP::compute(int eflag, int vflag) v0=v1=v2=v3=v4=v5=0.0; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) reduction(+:eng_tmp,v0,v1,v2,v3,v4,v5) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) reduction(+:eng_tmp,v0,v1,v2,v3,v4,v5) #endif { @@ -234,7 +235,7 @@ void EwaldOMP::eik_dot_r() const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int i,ifrom,ito,k,l,m,n,ic,tid; diff --git a/src/USER-OMP/fix_gravity_omp.cpp b/src/USER-OMP/fix_gravity_omp.cpp index 5bc1085f34..830fa0c4eb 100644 --- a/src/USER-OMP/fix_gravity_omp.cpp +++ b/src/USER-OMP/fix_gravity_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_gravity_omp.h" #include "atom.h" #include "update.h" @@ -69,7 +70,7 @@ void FixGravityOMP::post_force(int /* vflag */) if (rmass) { #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(-:grav) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(-:grav) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { @@ -81,7 +82,7 @@ void FixGravityOMP::post_force(int /* vflag */) } } else { #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(-:grav) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(-:grav) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { diff --git a/src/USER-OMP/fix_neigh_history_omp.cpp b/src/USER-OMP/fix_neigh_history_omp.cpp index 22d3fa944c..7acded0ab2 100644 --- a/src/USER-OMP/fix_neigh_history_omp.cpp +++ b/src/USER-OMP/fix_neigh_history_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_neigh_history_omp.h" #include #include "my_page.h" @@ -73,7 +74,7 @@ void FixNeighHistoryOMP::pre_exchange_onesided() maxpartner = 0; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { @@ -199,7 +200,7 @@ void FixNeighHistoryOMP::pre_exchange_newton() for (int i = 0; i < nall_neigh; i++) npartner[i] = 0; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { @@ -373,7 +374,7 @@ void FixNeighHistoryOMP::pre_exchange_no_newton() maxpartner = 0; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { @@ -525,7 +526,7 @@ void FixNeighHistoryOMP::post_neighbor() #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { diff --git a/src/USER-OMP/fix_nh_asphere_omp.cpp b/src/USER-OMP/fix_nh_asphere_omp.cpp index 185eab5f47..9c7317bebd 100644 --- a/src/USER-OMP/fix_nh_asphere_omp.cpp +++ b/src/USER-OMP/fix_nh_asphere_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include @@ -82,7 +83,7 @@ void FixNHAsphereOMP::nve_v() // merged with FixNHOMP instead of calling it for the COM update. #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -122,7 +123,7 @@ void FixNHAsphereOMP::nve_x() // principal moments of inertia #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { @@ -163,7 +164,7 @@ void FixNHAsphereOMP::nh_v_temp() if (which == NOBIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -177,7 +178,7 @@ void FixNHAsphereOMP::nh_v_temp() } } else if (which == BIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { double buf[3]; diff --git a/src/USER-OMP/fix_nh_omp.cpp b/src/USER-OMP/fix_nh_omp.cpp index d584bcd11f..b30169b2dc 100644 --- a/src/USER-OMP/fix_nh_omp.cpp +++ b/src/USER-OMP/fix_nh_omp.cpp @@ -15,6 +15,7 @@ Contributing authors: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_nh_omp.h" #include #include "atom.h" @@ -57,7 +58,7 @@ void FixNHOMP::remap() if (allremap) domain->x2lamda(nlocal); else { #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & dilate_group_bit) @@ -207,7 +208,7 @@ void FixNHOMP::remap() if (allremap) domain->lamda2x(nlocal); else { #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & dilate_group_bit) @@ -235,7 +236,7 @@ void FixNHOMP::nh_v_press() if (which == NOBIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -253,7 +254,7 @@ void FixNHOMP::nh_v_press() } } else if (which == BIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { double buf[3]; @@ -289,7 +290,7 @@ void FixNHOMP::nve_v() if (atom->rmass) { const double * _noalias const rmass = atom->rmass; #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -303,7 +304,7 @@ void FixNHOMP::nve_v() const double *_noalias const mass = atom->mass; const int * _noalias const type = atom->type; #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -330,7 +331,7 @@ void FixNHOMP::nve_x() // x update by full step only for atoms in group #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -352,7 +353,7 @@ void FixNHOMP::nh_v_temp() if (which == NOBIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -363,7 +364,7 @@ void FixNHOMP::nh_v_temp() } } else if (which == BIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { double buf[3]; diff --git a/src/USER-OMP/fix_nh_sphere_omp.cpp b/src/USER-OMP/fix_nh_sphere_omp.cpp index 0048ae7ff7..dd9a8addf4 100644 --- a/src/USER-OMP/fix_nh_sphere_omp.cpp +++ b/src/USER-OMP/fix_nh_sphere_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_nh_sphere_omp.h" #include "atom.h" #include "compute.h" @@ -85,7 +86,7 @@ void FixNHSphereOMP::nve_v() // 4 cases depending on radius vs shape and rmass vs mass #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -115,7 +116,7 @@ void FixNHSphereOMP::nh_v_temp() if (which == NOBIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -129,7 +130,7 @@ void FixNHSphereOMP::nh_v_temp() } } else if (which == BIAS) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) { double buf[3]; diff --git a/src/USER-OMP/fix_nve_omp.cpp b/src/USER-OMP/fix_nve_omp.cpp index f693c2fa20..13c1dfb642 100644 --- a/src/USER-OMP/fix_nve_omp.cpp +++ b/src/USER-OMP/fix_nve_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_nve_omp.h" #include "atom.h" @@ -41,7 +42,7 @@ void FixNVEOMP::initial_integrate(int /* vflag */) if (atom->rmass) { const double * const rmass = atom->rmass; #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { @@ -58,7 +59,7 @@ void FixNVEOMP::initial_integrate(int /* vflag */) const double * const mass = atom->mass; const int * const type = atom->type; #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { @@ -87,7 +88,7 @@ void FixNVEOMP::final_integrate() if (atom->rmass) { const double * const rmass = atom->rmass; #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { @@ -101,7 +102,7 @@ void FixNVEOMP::final_integrate() const double * const mass = atom->mass; const int * const type = atom->type; #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { diff --git a/src/USER-OMP/fix_nve_sphere_omp.cpp b/src/USER-OMP/fix_nve_sphere_omp.cpp index bc7be4019c..4a1bd4dfda 100644 --- a/src/USER-OMP/fix_nve_sphere_omp.cpp +++ b/src/USER-OMP/fix_nve_sphere_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_nve_sphere_omp.h" #include #include "atom.h" @@ -49,7 +50,7 @@ void FixNVESphereOMP::initial_integrate(int /* vflag */) // update v,x,omega for all particles // d_omega/dt = torque / inertia #if defined(_OPENMP) -#pragma omp parallel for default(none) +#pragma omp parallel for LMP_DEFAULT_NONE #endif for (int i = 0; i < nlocal; i++) { if (mask[i] & groupbit) { @@ -76,7 +77,7 @@ void FixNVESphereOMP::initial_integrate(int /* vflag */) double * const * const mu = atom->mu; if (dlm == NODLM) { #if defined(_OPENMP) -#pragma omp parallel for default(none) +#pragma omp parallel for LMP_DEFAULT_NONE #endif for (int i = 0; i < nlocal; i++) { double g0,g1,g2,msq,scale; @@ -95,7 +96,7 @@ void FixNVESphereOMP::initial_integrate(int /* vflag */) } } else { #if defined(_OPENMP) -#pragma omp parallel for default(none) +#pragma omp parallel for LMP_DEFAULT_NONE #endif // Integrate orientation following Dullweber-Leimkuhler-Maclachlan scheme for (int i = 0; i < nlocal; i++) { @@ -223,7 +224,7 @@ void FixNVESphereOMP::final_integrate() // d_omega/dt = torque / inertia #if defined(_OPENMP) -#pragma omp parallel for default(none) +#pragma omp parallel for LMP_DEFAULT_NONE #endif for (int i = 0; i < nlocal; i++) if (mask[i] & groupbit) { diff --git a/src/USER-OMP/fix_nvt_sllod_omp.cpp b/src/USER-OMP/fix_nvt_sllod_omp.cpp index 9b3b515415..0d23d6c03f 100644 --- a/src/USER-OMP/fix_nvt_sllod_omp.cpp +++ b/src/USER-OMP/fix_nvt_sllod_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_nvt_sllod_omp.h" #include #include "math_extra.h" @@ -114,7 +115,7 @@ void FixNVTSllodOMP::nh_v_temp() MathExtra::multiply_shape_shape(domain->h_rate,domain->h_inv,h_two); #if defined(_OPENMP) -#pragma omp parallel for default(none) shared(h_two) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE LMP_SHARED(h_two) schedule(static) #endif for (int i = 0; i < nlocal; i++) { double vdelu0,vdelu1,vdelu2,buf[3]; diff --git a/src/USER-OMP/fix_omp.cpp b/src/USER-OMP/fix_omp.cpp index 1fca1e739b..25a3a09816 100644 --- a/src/USER-OMP/fix_omp.cpp +++ b/src/USER-OMP/fix_omp.cpp @@ -16,6 +16,7 @@ OpenMP based threading support for LAMMPS ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "atom.h" #include "comm.h" #include "error.h" @@ -70,7 +71,7 @@ FixOMP::FixOMP(LAMMPS *lmp, int narg, char **arg) if (narg > 3) { #if defined(_OPENMP) if (strcmp(arg[3],"0") == 0) -#pragma omp parallel default(none) shared(nthreads) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(nthreads) nthreads = omp_get_num_threads(); else nthreads = force->inumeric(FLERR,arg[3]); @@ -134,7 +135,7 @@ FixOMP::FixOMP(LAMMPS *lmp, int narg, char **arg) thr = new ThrData *[nthreads]; _nthr = nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(lmp) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(lmp) #endif { const int tid = get_tid(); @@ -186,7 +187,7 @@ void FixOMP::init() thr = new ThrData *[nthreads]; _nthr = nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const int tid = get_tid(); @@ -350,7 +351,7 @@ void FixOMP::pre_force(int) double *drho = atom->drho; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(f,torque,erforce,de,drho) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(f,torque,erforce,de,drho) #endif { const int tid = get_tid(); diff --git a/src/USER-OMP/fix_rigid_nh_omp.cpp b/src/USER-OMP/fix_rigid_nh_omp.cpp index da512cb428..63084fcc9e 100644 --- a/src/USER-OMP/fix_rigid_nh_omp.cpp +++ b/src/USER-OMP/fix_rigid_nh_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_rigid_nh_omp.h" #include #include @@ -89,7 +90,7 @@ void FixRigidNHOMP::initial_integrate(int vflag) double akt=0.0, akr=0.0; #if defined(_OPENMP) -#pragma omp parallel for default(none) shared(scale_r,scale_t,scale_v) schedule(static) reduction(+:akt,akr) +#pragma omp parallel for LMP_DEFAULT_NONE LMP_SHARED(scale_r,scale_t,scale_v) schedule(static) reduction(+:akt,akr) #endif for (int ibody = 0; ibody < nbody; ibody++) { double mbody[3],tbody[3],fquat[4]; @@ -250,7 +251,7 @@ void FixRigidNHOMP::compute_forces_and_torques() int i; #if defined(_OPENMP) -#pragma omp parallel for default(none) private(i) reduction(+:s0,s1,s2,s3,s4,s5) +#pragma omp parallel for LMP_DEFAULT_NONE private(i) reduction(+:s0,s1,s2,s3,s4,s5) #endif for (i = 0; i < nlocal; i++) { const int ibody = body[i]; @@ -289,7 +290,7 @@ void FixRigidNHOMP::compute_forces_and_torques() int i; #if defined(_OPENMP) -#pragma omp parallel for default(none) private(i) shared(ib) reduction(+:s0,s1,s2,s3,s4,s5) +#pragma omp parallel for LMP_DEFAULT_NONE private(i) LMP_SHARED(ib) reduction(+:s0,s1,s2,s3,s4,s5) #endif for (i = 0; i < nlocal; i++) { const int ibody = body[i]; @@ -330,7 +331,7 @@ void FixRigidNHOMP::compute_forces_and_torques() memset(&sum[0][0],0,6*nbody*sizeof(double)); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -373,7 +374,7 @@ void FixRigidNHOMP::compute_forces_and_torques() MPI_Allreduce(sum[0],all[0],6*nbody,MPI_DOUBLE,MPI_SUM,world); #if defined(_OPENMP) -#pragma omp parallel for default(none) private(ibody) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE private(ibody) schedule(static) #endif for (ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] = all[ibody][0] + langextra[ibody][0]; @@ -388,7 +389,7 @@ void FixRigidNHOMP::compute_forces_and_torques() if (id_gravity) { #if defined(_OPENMP) -#pragma omp parallel for default(none) private(ibody) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE private(ibody) schedule(static) #endif for (ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] += gvec[0]*masstotal[ibody]; @@ -433,7 +434,7 @@ void FixRigidNHOMP::final_integrate() const double dtf2 = dtf * 2.0; #if defined(_OPENMP) -#pragma omp parallel for default(none) shared(scale_t,scale_r) schedule(static) reduction(+:akt,akr) +#pragma omp parallel for LMP_DEFAULT_NONE LMP_SHARED(scale_t,scale_r) schedule(static) reduction(+:akt,akr) #endif for (int ibody = 0; ibody < nbody; ibody++) { double mbody[3],tbody[3],fquat[4]; @@ -554,7 +555,7 @@ void FixRigidNHOMP::remap() if (allremap) domain->x2lamda(nlocal); else { #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & dilate_group_bit) @@ -586,7 +587,7 @@ void FixRigidNHOMP::remap() if (allremap) domain->lamda2x(nlocal); else { #if defined (_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int i = 0; i < nlocal; i++) if (mask[i] & dilate_group_bit) @@ -631,7 +632,7 @@ void FixRigidNHOMP::set_xv_thr() int i; #if defined(_OPENMP) -#pragma omp parallel for default(none) private(i) reduction(+:v0,v1,v2,v3,v4,v5) +#pragma omp parallel for LMP_DEFAULT_NONE private(i) reduction(+:v0,v1,v2,v3,v4,v5) #endif for (i = 0; i < nlocal; i++) { const int ibody = body[i]; @@ -832,7 +833,7 @@ void FixRigidNHOMP::set_v_thr() int i; #if defined(_OPENMP) -#pragma omp parallel for default(none) private(i) reduction(+:v0,v1,v2,v3,v4,v5) +#pragma omp parallel for LMP_DEFAULT_NONE private(i) reduction(+:v0,v1,v2,v3,v4,v5) #endif for (i = 0; i < nlocal; i++) { const int ibody = body[i]; diff --git a/src/USER-OMP/fix_rigid_omp.cpp b/src/USER-OMP/fix_rigid_omp.cpp index 770361d557..9f78f6dc26 100644 --- a/src/USER-OMP/fix_rigid_omp.cpp +++ b/src/USER-OMP/fix_rigid_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_rigid_omp.h" #include #include @@ -47,7 +48,7 @@ typedef struct { double x,y,z; } dbl3_t; void FixRigidOMP::initial_integrate(int vflag) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nbody; ibody++) { @@ -120,7 +121,7 @@ void FixRigidOMP::compute_forces_and_torques() double s0=0.0,s1=0.0,s2=0.0,s3=0.0,s4=0.0,s5=0.0; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:s0,s1,s2,s3,s4,s5) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:s0,s1,s2,s3,s4,s5) #endif for (int i = 0; i < nlocal; i++) { const int ibody = body[i]; @@ -158,7 +159,7 @@ void FixRigidOMP::compute_forces_and_torques() double s0=0.0,s1=0.0,s2=0.0,s3=0.0,s4=0.0,s5=0.0; #if defined(_OPENMP) -#pragma omp parallel for default(none) shared(ib) reduction(+:s0,s1,s2,s3,s4,s5) +#pragma omp parallel for LMP_DEFAULT_NONE LMP_SHARED(ib) reduction(+:s0,s1,s2,s3,s4,s5) #endif for (int i = 0; i < nlocal; i++) { const int ibody = body[i]; @@ -199,7 +200,7 @@ void FixRigidOMP::compute_forces_and_torques() memset(&sum[0][0],0,6*nbody*sizeof(double)); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -246,7 +247,7 @@ void FixRigidOMP::compute_forces_and_torques() // fflag,tflag = 0 for some dimensions in 2d #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] = all[ibody][0] + langextra[ibody][0]; @@ -261,7 +262,7 @@ void FixRigidOMP::compute_forces_and_torques() if (id_gravity) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nbody; ibody++) { fcm[ibody][0] += gvec[0]*masstotal[ibody]; @@ -280,7 +281,7 @@ void FixRigidOMP::final_integrate() // update vcm and angmom #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nbody; ibody++) { @@ -346,7 +347,7 @@ void FixRigidOMP::set_xv_thr() const int nlocal = atom->nlocal; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:v0,v1,v2,v3,v4,v5) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:v0,v1,v2,v3,v4,v5) #endif for (int i = 0; i < nlocal; i++) { const int ibody = body[i]; @@ -546,7 +547,7 @@ void FixRigidOMP::set_v_thr() const int nlocal = atom->nlocal; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:v0,v1,v2,v3,v4,v5) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:v0,v1,v2,v3,v4,v5) #endif for (int i = 0; i < nlocal; i++) { const int ibody = body[i]; diff --git a/src/USER-OMP/fix_rigid_small_omp.cpp b/src/USER-OMP/fix_rigid_small_omp.cpp index fc6b6fa57a..227b0e1f8a 100644 --- a/src/USER-OMP/fix_rigid_small_omp.cpp +++ b/src/USER-OMP/fix_rigid_small_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "fix_rigid_small_omp.h" #include #include "atom.h" @@ -46,7 +47,7 @@ void FixRigidSmallOMP::initial_integrate(int vflag) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nlocal_body; ibody++) { @@ -117,7 +118,7 @@ void FixRigidSmallOMP::compute_forces_and_torques() const int nthreads=comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nlocal_body+nghost_body; ibody++) { double * _noalias const fcm = body[ibody].fcm; @@ -132,7 +133,7 @@ void FixRigidSmallOMP::compute_forces_and_torques() // and then each thread only processes some bodies. #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -183,7 +184,7 @@ void FixRigidSmallOMP::compute_forces_and_torques() if (langflag) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nlocal_body; ibody++) { double * _noalias const fcm = body[ibody].fcm; @@ -201,7 +202,7 @@ void FixRigidSmallOMP::compute_forces_and_torques() if (id_gravity) { #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nbody; ibody++) { double * _noalias const fcm = body[ibody].fcm; @@ -222,7 +223,7 @@ void FixRigidSmallOMP::final_integrate() // update vcm and angmom, recompute omega #if defined(_OPENMP) -#pragma omp parallel for default(none) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE schedule(static) #endif for (int ibody = 0; ibody < nlocal_body; ibody++) { Body &b = body[ibody]; @@ -294,7 +295,7 @@ void FixRigidSmallOMP::set_xv_thr() const int nlocal = atom->nlocal; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:v0,v1,v2,v3,v4,v5) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:v0,v1,v2,v3,v4,v5) #endif for (int i = 0; i < nlocal; i++) { const int ibody = atom2body[i]; @@ -489,7 +490,7 @@ void FixRigidSmallOMP::set_v_thr() const int nlocal = atom->nlocal; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:v0,v1,v2,v3,v4,v5) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:v0,v1,v2,v3,v4,v5) #endif for (int i = 0; i < nlocal; i++) { const int ibody = atom2body[i]; diff --git a/src/USER-OMP/improper_class2_omp.cpp b/src/USER-OMP/improper_class2_omp.cpp index 32c7406ada..8927980951 100644 --- a/src/USER-OMP/improper_class2_omp.cpp +++ b/src/USER-OMP/improper_class2_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "improper_class2_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void ImproperClass2OMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/improper_cossq_omp.cpp b/src/USER-OMP/improper_cossq_omp.cpp index 230f13eac7..72d76e8c42 100644 --- a/src/USER-OMP/improper_cossq_omp.cpp +++ b/src/USER-OMP/improper_cossq_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "improper_cossq_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void ImproperCossqOMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/improper_cvff_omp.cpp b/src/USER-OMP/improper_cvff_omp.cpp index f5ff590775..e9ff4bfc73 100644 --- a/src/USER-OMP/improper_cvff_omp.cpp +++ b/src/USER-OMP/improper_cvff_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "improper_cvff_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void ImproperCvffOMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/improper_fourier_omp.cpp b/src/USER-OMP/improper_fourier_omp.cpp index 4e83c025d0..0671bdc375 100644 --- a/src/USER-OMP/improper_fourier_omp.cpp +++ b/src/USER-OMP/improper_fourier_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "improper_fourier_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void ImproperFourierOMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/improper_harmonic_omp.cpp b/src/USER-OMP/improper_harmonic_omp.cpp index f2f19557d9..8bef42bf23 100644 --- a/src/USER-OMP/improper_harmonic_omp.cpp +++ b/src/USER-OMP/improper_harmonic_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "improper_harmonic_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void ImproperHarmonicOMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/improper_ring_omp.cpp b/src/USER-OMP/improper_ring_omp.cpp index 1d0cc6cc46..4ba67aab70 100644 --- a/src/USER-OMP/improper_ring_omp.cpp +++ b/src/USER-OMP/improper_ring_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "improper_ring_omp.h" #include #include "atom.h" @@ -50,7 +51,7 @@ void ImproperRingOMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/improper_umbrella_omp.cpp b/src/USER-OMP/improper_umbrella_omp.cpp index 4cea8a4b63..bf466afb19 100644 --- a/src/USER-OMP/improper_umbrella_omp.cpp +++ b/src/USER-OMP/improper_umbrella_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "improper_umbrella_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void ImproperUmbrellaOMP::compute(int eflag, int vflag) const int inum = neighbor->nimproperlist; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/msm_cg_omp.cpp b/src/USER-OMP/msm_cg_omp.cpp index 7ca01dbd6a..16db4857d6 100644 --- a/src/USER-OMP/msm_cg_omp.cpp +++ b/src/USER-OMP/msm_cg_omp.cpp @@ -16,6 +16,7 @@ Original MSM class by: Paul Crozier, Stan Moore, Stephen Bond, (all SNL) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "msm_cg_omp.h" #include #include @@ -310,7 +311,7 @@ void MSMCGOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) diff --git a/src/USER-OMP/msm_omp.cpp b/src/USER-OMP/msm_omp.cpp index 81f84e8f6f..2689226725 100644 --- a/src/USER-OMP/msm_omp.cpp +++ b/src/USER-OMP/msm_omp.cpp @@ -15,6 +15,7 @@ Contributing authors: Axel Kohlmeyer (Temple U), Stan Moore (SNL) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "msm_omp.h" #include #include "comm.h" @@ -52,7 +53,7 @@ void MSMOMP::compute(int eflag, int vflag) MSM::compute(eflag,vflag); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) @@ -158,7 +159,7 @@ void MSMOMP::direct_eval(const int nn) const int n=nn; #if defined(_OPENMP) -#pragma omp parallel default(none) reduction(+:v0,v1,v2,v3,v4,v5,emsm) +#pragma omp parallel LMP_DEFAULT_NONE reduction(+:v0,v1,v2,v3,v4,v5,emsm) #endif { double esum,v0sum,v1sum,v2sum,v3sum,v4sum,v5sum; diff --git a/src/USER-OMP/npair_full_bin_atomonly_omp.cpp b/src/USER-OMP/npair_full_bin_atomonly_omp.cpp index 3bda2e4c5a..226b2dcf6d 100644 --- a/src/USER-OMP/npair_full_bin_atomonly_omp.cpp +++ b/src/USER-OMP/npair_full_bin_atomonly_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_full_bin_atomonly_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -36,7 +37,7 @@ void NPairFullBinAtomonlyOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_full_bin_ghost_omp.cpp b/src/USER-OMP/npair_full_bin_ghost_omp.cpp index b0b0070df5..e9297538d9 100644 --- a/src/USER-OMP/npair_full_bin_ghost_omp.cpp +++ b/src/USER-OMP/npair_full_bin_ghost_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_full_bin_ghost_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -42,7 +43,7 @@ void NPairFullBinGhostOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nall); diff --git a/src/USER-OMP/npair_full_bin_omp.cpp b/src/USER-OMP/npair_full_bin_omp.cpp index d3e30b4932..35835cae1d 100644 --- a/src/USER-OMP/npair_full_bin_omp.cpp +++ b/src/USER-OMP/npair_full_bin_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_full_bin_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -40,7 +41,7 @@ void NPairFullBinOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_full_multi_omp.cpp b/src/USER-OMP/npair_full_multi_omp.cpp index 707db2edcf..b4b0ea3033 100644 --- a/src/USER-OMP/npair_full_multi_omp.cpp +++ b/src/USER-OMP/npair_full_multi_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_full_multi_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -41,7 +42,7 @@ void NPairFullMultiOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_full_nsq_ghost_omp.cpp b/src/USER-OMP/npair_full_nsq_ghost_omp.cpp index 527df58fd6..8b940f3724 100644 --- a/src/USER-OMP/npair_full_nsq_ghost_omp.cpp +++ b/src/USER-OMP/npair_full_nsq_ghost_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_full_nsq_ghost_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -42,7 +43,7 @@ void NPairFullNsqGhostOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nall); diff --git a/src/USER-OMP/npair_full_nsq_omp.cpp b/src/USER-OMP/npair_full_nsq_omp.cpp index 2719f5dc2c..95c5caa148 100644 --- a/src/USER-OMP/npair_full_nsq_omp.cpp +++ b/src/USER-OMP/npair_full_nsq_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_full_nsq_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -42,7 +43,7 @@ void NPairFullNsqOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_bin_atomonly_newton_omp.cpp b/src/USER-OMP/npair_half_bin_atomonly_newton_omp.cpp index a69779d96d..230d10a267 100644 --- a/src/USER-OMP/npair_half_bin_atomonly_newton_omp.cpp +++ b/src/USER-OMP/npair_half_bin_atomonly_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_bin_atomonly_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -37,7 +38,7 @@ void NPairHalfBinAtomonlyNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_bin_newtoff_ghost_omp.cpp b/src/USER-OMP/npair_half_bin_newtoff_ghost_omp.cpp index 5f8ffdab29..33fa4ed685 100644 --- a/src/USER-OMP/npair_half_bin_newtoff_ghost_omp.cpp +++ b/src/USER-OMP/npair_half_bin_newtoff_ghost_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_bin_newtoff_ghost_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -46,7 +47,7 @@ void NPairHalfBinNewtoffGhostOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nall); diff --git a/src/USER-OMP/npair_half_bin_newtoff_omp.cpp b/src/USER-OMP/npair_half_bin_newtoff_omp.cpp index 35807645cf..8e756d5072 100644 --- a/src/USER-OMP/npair_half_bin_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_bin_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_bin_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -42,7 +43,7 @@ void NPairHalfBinNewtoffOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_bin_newton_omp.cpp b/src/USER-OMP/npair_half_bin_newton_omp.cpp index 2700d6863b..e27a58de46 100644 --- a/src/USER-OMP/npair_half_bin_newton_omp.cpp +++ b/src/USER-OMP/npair_half_bin_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_bin_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -41,7 +42,7 @@ void NPairHalfBinNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_bin_newton_tri_omp.cpp b/src/USER-OMP/npair_half_bin_newton_tri_omp.cpp index d94845898c..f88df4aed4 100644 --- a/src/USER-OMP/npair_half_bin_newton_tri_omp.cpp +++ b/src/USER-OMP/npair_half_bin_newton_tri_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_bin_newton_tri_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -41,7 +42,7 @@ void NPairHalfBinNewtonTriOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_multi_newtoff_omp.cpp b/src/USER-OMP/npair_half_multi_newtoff_omp.cpp index c06737dc1c..586809c174 100644 --- a/src/USER-OMP/npair_half_multi_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_multi_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_multi_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -43,7 +44,7 @@ void NPairHalfMultiNewtoffOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_multi_newton_omp.cpp b/src/USER-OMP/npair_half_multi_newton_omp.cpp index 50df756be4..9b8fc78f09 100644 --- a/src/USER-OMP/npair_half_multi_newton_omp.cpp +++ b/src/USER-OMP/npair_half_multi_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_multi_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -42,7 +43,7 @@ void NPairHalfMultiNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_multi_newton_tri_omp.cpp b/src/USER-OMP/npair_half_multi_newton_tri_omp.cpp index 8b78b311dd..fec687d075 100644 --- a/src/USER-OMP/npair_half_multi_newton_tri_omp.cpp +++ b/src/USER-OMP/npair_half_multi_newton_tri_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_multi_newton_tri_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -43,7 +44,7 @@ void NPairHalfMultiNewtonTriOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_nsq_newtoff_ghost_omp.cpp b/src/USER-OMP/npair_half_nsq_newtoff_ghost_omp.cpp index f0eb211425..316c63d541 100644 --- a/src/USER-OMP/npair_half_nsq_newtoff_ghost_omp.cpp +++ b/src/USER-OMP/npair_half_nsq_newtoff_ghost_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_nsq_newtoff_ghost_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -47,7 +48,7 @@ void NPairHalfNsqNewtoffGhostOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nall); diff --git a/src/USER-OMP/npair_half_nsq_newtoff_omp.cpp b/src/USER-OMP/npair_half_nsq_newtoff_omp.cpp index 55b9f9e512..c937b5bc68 100644 --- a/src/USER-OMP/npair_half_nsq_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_nsq_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_nsq_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -44,7 +45,7 @@ void NPairHalfNsqNewtoffOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_nsq_newton_omp.cpp b/src/USER-OMP/npair_half_nsq_newton_omp.cpp index 223da622e8..6baab97aa0 100644 --- a/src/USER-OMP/npair_half_nsq_newton_omp.cpp +++ b/src/USER-OMP/npair_half_nsq_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_nsq_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -43,7 +44,7 @@ void NPairHalfNsqNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_respa_bin_newtoff_omp.cpp b/src/USER-OMP/npair_half_respa_bin_newtoff_omp.cpp index 9bb4d277fe..c8dc37f978 100644 --- a/src/USER-OMP/npair_half_respa_bin_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_respa_bin_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_respa_bin_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -47,7 +48,7 @@ void NPairHalfRespaBinNewtoffOmp::build(NeighList *list) const int respamiddle = list->respamiddle; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_respa_bin_newton_omp.cpp b/src/USER-OMP/npair_half_respa_bin_newton_omp.cpp index 9ed0ae482d..98732a62ea 100644 --- a/src/USER-OMP/npair_half_respa_bin_newton_omp.cpp +++ b/src/USER-OMP/npair_half_respa_bin_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_respa_bin_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -46,7 +47,7 @@ void NPairHalfRespaBinNewtonOmp::build(NeighList *list) const int respamiddle = list->respamiddle; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_respa_bin_newton_tri_omp.cpp b/src/USER-OMP/npair_half_respa_bin_newton_tri_omp.cpp index cd03684940..65315a2905 100644 --- a/src/USER-OMP/npair_half_respa_bin_newton_tri_omp.cpp +++ b/src/USER-OMP/npair_half_respa_bin_newton_tri_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_respa_bin_newton_tri_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -46,7 +47,7 @@ void NPairHalfRespaBinNewtonTriOmp::build(NeighList *list) const int respamiddle = list->respamiddle; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_respa_nsq_newtoff_omp.cpp b/src/USER-OMP/npair_half_respa_nsq_newtoff_omp.cpp index b1e7467ec7..45d81069fc 100644 --- a/src/USER-OMP/npair_half_respa_nsq_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_respa_nsq_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_respa_nsq_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -48,7 +49,7 @@ void NPairHalfRespaNsqNewtoffOmp::build(NeighList *list) const int respamiddle = list->respamiddle; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_respa_nsq_newton_omp.cpp b/src/USER-OMP/npair_half_respa_nsq_newton_omp.cpp index c22965895d..1237ce7858 100644 --- a/src/USER-OMP/npair_half_respa_nsq_newton_omp.cpp +++ b/src/USER-OMP/npair_half_respa_nsq_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_respa_nsq_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -49,7 +50,7 @@ void NPairHalfRespaNsqNewtonOmp::build(NeighList *list) const int respamiddle = list->respamiddle; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_size_bin_newtoff_omp.cpp b/src/USER-OMP/npair_half_size_bin_newtoff_omp.cpp index 1b437482c4..c979c1384d 100644 --- a/src/USER-OMP/npair_half_size_bin_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_size_bin_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_size_bin_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -43,7 +44,7 @@ void NPairHalfSizeBinNewtoffOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_size_bin_newton_omp.cpp b/src/USER-OMP/npair_half_size_bin_newton_omp.cpp index 8e0581d4ce..c83cf77e50 100644 --- a/src/USER-OMP/npair_half_size_bin_newton_omp.cpp +++ b/src/USER-OMP/npair_half_size_bin_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_size_bin_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -42,7 +43,7 @@ void NPairHalfSizeBinNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_size_bin_newton_tri_omp.cpp b/src/USER-OMP/npair_half_size_bin_newton_tri_omp.cpp index 38a2c0d61f..a615b11d93 100644 --- a/src/USER-OMP/npair_half_size_bin_newton_tri_omp.cpp +++ b/src/USER-OMP/npair_half_size_bin_newton_tri_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_size_bin_newton_tri_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -41,7 +42,7 @@ void NPairHalfSizeBinNewtonTriOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_size_nsq_newtoff_omp.cpp b/src/USER-OMP/npair_half_size_nsq_newtoff_omp.cpp index d1505e1b2e..f42cc3e9bf 100644 --- a/src/USER-OMP/npair_half_size_nsq_newtoff_omp.cpp +++ b/src/USER-OMP/npair_half_size_nsq_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_size_nsq_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -45,7 +46,7 @@ void NPairHalfSizeNsqNewtoffOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_half_size_nsq_newton_omp.cpp b/src/USER-OMP/npair_half_size_nsq_newton_omp.cpp index 9027b0728d..10d7d26b3d 100644 --- a/src/USER-OMP/npair_half_size_nsq_newton_omp.cpp +++ b/src/USER-OMP/npair_half_size_nsq_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_half_size_nsq_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -46,7 +47,7 @@ void NPairHalfSizeNsqNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(nlocal); diff --git a/src/USER-OMP/npair_halffull_newtoff_omp.cpp b/src/USER-OMP/npair_halffull_newtoff_omp.cpp index 7d2fe4f109..7ad0157076 100644 --- a/src/USER-OMP/npair_halffull_newtoff_omp.cpp +++ b/src/USER-OMP/npair_halffull_newtoff_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_halffull_newtoff_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -38,7 +39,7 @@ void NPairHalffullNewtoffOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(inum_full); diff --git a/src/USER-OMP/npair_halffull_newton_omp.cpp b/src/USER-OMP/npair_halffull_newton_omp.cpp index 3fcc8c2e98..9e248ee609 100644 --- a/src/USER-OMP/npair_halffull_newton_omp.cpp +++ b/src/USER-OMP/npair_halffull_newton_omp.cpp @@ -11,6 +11,7 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "npair_halffull_newton_omp.h" #include "npair_omp.h" #include "neigh_list.h" @@ -38,7 +39,7 @@ void NPairHalffullNewtonOmp::build(NeighList *list) NPAIR_OMP_INIT; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(list) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(list) #endif NPAIR_OMP_SETUP(inum_full); diff --git a/src/USER-OMP/pair_adp_omp.cpp b/src/USER-OMP/pair_adp_omp.cpp index 0a48de453e..63a539c93c 100644 --- a/src/USER-OMP/pair_adp_omp.cpp +++ b/src/USER-OMP/pair_adp_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include @@ -62,7 +63,7 @@ void PairADPOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_agni_omp.cpp b/src/USER-OMP/pair_agni_omp.cpp index 1580256e35..b61bf52e4e 100644 --- a/src/USER-OMP/pair_agni_omp.cpp +++ b/src/USER-OMP/pair_agni_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include // requires C++-11 @@ -49,7 +50,7 @@ void PairAGNIOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_airebo_omp.cpp b/src/USER-OMP/pair_airebo_omp.cpp index aedf5056a6..25d6c35174 100644 --- a/src/USER-OMP/pair_airebo_omp.cpp +++ b/src/USER-OMP/pair_airebo_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_airebo_omp.h" #include "atom.h" @@ -58,7 +59,7 @@ void PairAIREBOOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) reduction(+:pv0,pv1,pv2) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) reduction(+:pv0,pv1,pv2) #endif { int ifrom, ito, tid; @@ -104,7 +105,7 @@ void PairAIREBOOMP::REBO_neigh_thr() } #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int i,j,ii,jj,n,jnum,itype,jtype; diff --git a/src/USER-OMP/pair_beck_omp.cpp b/src/USER-OMP/pair_beck_omp.cpp index 72e41f074c..48e6f9b0fe 100644 --- a/src/USER-OMP/pair_beck_omp.cpp +++ b/src/USER-OMP/pair_beck_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_beck_omp.h" #include #include "atom.h" @@ -45,7 +46,7 @@ void PairBeckOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_born_coul_long_omp.cpp b/src/USER-OMP/pair_born_coul_long_omp.cpp index f7e3fced46..7f92ab6734 100644 --- a/src/USER-OMP/pair_born_coul_long_omp.cpp +++ b/src/USER-OMP/pair_born_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_born_coul_long_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void PairBornCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_born_coul_msm_omp.cpp b/src/USER-OMP/pair_born_coul_msm_omp.cpp index b057cbc706..eec1765859 100644 --- a/src/USER-OMP/pair_born_coul_msm_omp.cpp +++ b/src/USER-OMP/pair_born_coul_msm_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_born_coul_msm_omp.h" #include "atom.h" @@ -48,7 +49,7 @@ void PairBornCoulMSMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_born_coul_wolf_omp.cpp b/src/USER-OMP/pair_born_coul_wolf_omp.cpp index bac38ae43a..ffa069ec4e 100644 --- a/src/USER-OMP/pair_born_coul_wolf_omp.cpp +++ b/src/USER-OMP/pair_born_coul_wolf_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_born_coul_wolf_omp.h" #include #include "atom.h" @@ -45,7 +46,7 @@ void PairBornCoulWolfOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_born_omp.cpp b/src/USER-OMP/pair_born_omp.cpp index 6cacd5625b..aaac28d07c 100644 --- a/src/USER-OMP/pair_born_omp.cpp +++ b/src/USER-OMP/pair_born_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_born_omp.h" #include #include "atom.h" @@ -43,7 +44,7 @@ void PairBornOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_brownian_omp.cpp b/src/USER-OMP/pair_brownian_omp.cpp index 907a447332..ca28fa14bb 100644 --- a/src/USER-OMP/pair_brownian_omp.cpp +++ b/src/USER-OMP/pair_brownian_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_brownian_omp.h" #include #include "atom.h" @@ -135,7 +136,7 @@ void PairBrownianOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_brownian_poly_omp.cpp b/src/USER-OMP/pair_brownian_poly_omp.cpp index f6f5f269a5..939bc223eb 100644 --- a/src/USER-OMP/pair_brownian_poly_omp.cpp +++ b/src/USER-OMP/pair_brownian_poly_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_brownian_poly_omp.h" #include #include "atom.h" @@ -135,7 +136,7 @@ void PairBrownianPolyOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_buck_coul_cut_omp.cpp b/src/USER-OMP/pair_buck_coul_cut_omp.cpp index c9ccb12447..2cff0d749d 100644 --- a/src/USER-OMP/pair_buck_coul_cut_omp.cpp +++ b/src/USER-OMP/pair_buck_coul_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_buck_coul_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairBuckCoulCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_buck_coul_long_omp.cpp b/src/USER-OMP/pair_buck_coul_long_omp.cpp index 0929157895..759a8b2118 100644 --- a/src/USER-OMP/pair_buck_coul_long_omp.cpp +++ b/src/USER-OMP/pair_buck_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_buck_coul_long_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void PairBuckCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_buck_coul_msm_omp.cpp b/src/USER-OMP/pair_buck_coul_msm_omp.cpp index a4d322890a..b26243b19a 100644 --- a/src/USER-OMP/pair_buck_coul_msm_omp.cpp +++ b/src/USER-OMP/pair_buck_coul_msm_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_buck_coul_msm_omp.h" #include "atom.h" @@ -48,7 +49,7 @@ void PairBuckCoulMSMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_buck_long_coul_long_omp.cpp b/src/USER-OMP/pair_buck_long_coul_long_omp.cpp index d30e8949b3..a2e34b9a1b 100644 --- a/src/USER-OMP/pair_buck_long_coul_long_omp.cpp +++ b/src/USER-OMP/pair_buck_long_coul_long_omp.cpp @@ -12,6 +12,7 @@ ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "math_vector.h" #include "pair_buck_long_coul_long_omp.h" @@ -56,7 +57,7 @@ void PairBuckLongCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; @@ -320,7 +321,7 @@ void PairBuckLongCoulLongOMP::compute_inner() const int nthreads = comm->nthreads; const int inum = list->inum_inner; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int ifrom, ito, tid; @@ -345,7 +346,7 @@ void PairBuckLongCoulLongOMP::compute_middle() const int inum = list->inum_middle; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int ifrom, ito, tid; @@ -375,7 +376,7 @@ void PairBuckLongCoulLongOMP::compute_outer(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_buck_omp.cpp b/src/USER-OMP/pair_buck_omp.cpp index 563133e1cd..fc85d79c81 100644 --- a/src/USER-OMP/pair_buck_omp.cpp +++ b/src/USER-OMP/pair_buck_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_buck_omp.h" #include #include "atom.h" @@ -43,7 +44,7 @@ void PairBuckOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_colloid_omp.cpp b/src/USER-OMP/pair_colloid_omp.cpp index 0fc4b1bdf2..cce588f516 100644 --- a/src/USER-OMP/pair_colloid_omp.cpp +++ b/src/USER-OMP/pair_colloid_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_colloid_omp.h" #include "atom.h" @@ -46,7 +47,7 @@ void PairColloidOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_comb_omp.cpp b/src/USER-OMP/pair_comb_omp.cpp index 4b5f0ea6c7..8912cbc243 100644 --- a/src/USER-OMP/pair_comb_omp.cpp +++ b/src/USER-OMP/pair_comb_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_comb_omp.h" #include "atom.h" @@ -52,7 +53,7 @@ void PairCombOMP::compute(int eflag, int vflag) Short_neigh_thr(); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; @@ -411,7 +412,7 @@ double PairCombOMP::yasu_char(double *qf_fix, int &igroup) // loop over full neighbor list of my atoms #if defined(_OPENMP) -#pragma omp parallel for private(ii) default(none) shared(potal,fac11e) +#pragma omp parallel for private(ii) LMP_DEFAULT_NONE LMP_SHARED(potal,fac11e) #endif for (ii = 0; ii < inum; ii ++) { double fqi,fqj,fqij,fqji,fqjj,delr1[3]; @@ -564,7 +565,7 @@ void PairCombOMP::Short_neigh_thr() const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int nj,*neighptrj; diff --git a/src/USER-OMP/pair_coul_cut_omp.cpp b/src/USER-OMP/pair_coul_cut_omp.cpp index ce858666cb..69eb9ac0f3 100644 --- a/src/USER-OMP/pair_coul_cut_omp.cpp +++ b/src/USER-OMP/pair_coul_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_coul_cut_omp.h" #include #include "atom.h" @@ -43,7 +44,7 @@ void PairCoulCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_cut_soft_omp.cpp b/src/USER-OMP/pair_coul_cut_soft_omp.cpp index 7b6ed22f0c..89222903ec 100644 --- a/src/USER-OMP/pair_coul_cut_soft_omp.cpp +++ b/src/USER-OMP/pair_coul_cut_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_coul_cut_soft_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairCoulCutSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_debye_omp.cpp b/src/USER-OMP/pair_coul_debye_omp.cpp index 270770ee5d..c22f7340c4 100644 --- a/src/USER-OMP/pair_coul_debye_omp.cpp +++ b/src/USER-OMP/pair_coul_debye_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_coul_debye_omp.h" #include #include "atom.h" @@ -43,7 +44,7 @@ void PairCoulDebyeOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_diel_omp.cpp b/src/USER-OMP/pair_coul_diel_omp.cpp index 67e09690de..656cdc9421 100644 --- a/src/USER-OMP/pair_coul_diel_omp.cpp +++ b/src/USER-OMP/pair_coul_diel_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_coul_diel_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairCoulDielOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_dsf_omp.cpp b/src/USER-OMP/pair_coul_dsf_omp.cpp index 40e285e7c8..ddcc8dbeb0 100644 --- a/src/USER-OMP/pair_coul_dsf_omp.cpp +++ b/src/USER-OMP/pair_coul_dsf_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_coul_dsf_omp.h" #include #include "atom.h" @@ -52,7 +53,7 @@ void PairCoulDSFOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_long_omp.cpp b/src/USER-OMP/pair_coul_long_omp.cpp index b135ffa7e6..6c9b9d034d 100644 --- a/src/USER-OMP/pair_coul_long_omp.cpp +++ b/src/USER-OMP/pair_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_coul_long_omp.h" #include "atom.h" @@ -52,7 +53,7 @@ void PairCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_long_soft_omp.cpp b/src/USER-OMP/pair_coul_long_soft_omp.cpp index 891123b8b3..ff3267fb38 100644 --- a/src/USER-OMP/pair_coul_long_soft_omp.cpp +++ b/src/USER-OMP/pair_coul_long_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_coul_long_soft_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void PairCoulLongSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_msm_omp.cpp b/src/USER-OMP/pair_coul_msm_omp.cpp index 9417df7ac6..32a657e286 100644 --- a/src/USER-OMP/pair_coul_msm_omp.cpp +++ b/src/USER-OMP/pair_coul_msm_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_coul_msm_omp.h" #include "atom.h" @@ -49,7 +50,7 @@ void PairCoulMSMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_coul_wolf_omp.cpp b/src/USER-OMP/pair_coul_wolf_omp.cpp index 9163eff086..d0f6fdb125 100644 --- a/src/USER-OMP/pair_coul_wolf_omp.cpp +++ b/src/USER-OMP/pair_coul_wolf_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_coul_wolf_omp.h" #include #include "atom.h" @@ -45,7 +46,7 @@ void PairCoulWolfOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_dpd_omp.cpp b/src/USER-OMP/pair_dpd_omp.cpp index 7c265b2b7b..f3a1c29a70 100644 --- a/src/USER-OMP/pair_dpd_omp.cpp +++ b/src/USER-OMP/pair_dpd_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_dpd_omp.h" #include #include "atom.h" @@ -80,7 +81,7 @@ void PairDPDOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_dpd_tstat_omp.cpp b/src/USER-OMP/pair_dpd_tstat_omp.cpp index 076e27a299..06e80274bd 100644 --- a/src/USER-OMP/pair_dpd_tstat_omp.cpp +++ b/src/USER-OMP/pair_dpd_tstat_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_dpd_tstat_omp.h" #include "atom.h" @@ -79,7 +80,7 @@ void PairDPDTstatOMP::compute(int eflag, int vflag) random_thr[0] = random; } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_eam_cd_omp.cpp b/src/USER-OMP/pair_eam_cd_omp.cpp index 1d945e06a8..874a2fa252 100644 --- a/src/USER-OMP/pair_eam_cd_omp.cpp +++ b/src/USER-OMP/pair_eam_cd_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include @@ -77,7 +78,7 @@ void PairEAMCDOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_eam_omp.cpp b/src/USER-OMP/pair_eam_omp.cpp index 899323a680..60ae65def5 100644 --- a/src/USER-OMP/pair_eam_omp.cpp +++ b/src/USER-OMP/pair_eam_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include @@ -59,7 +60,7 @@ void PairEAMOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_edip_omp.cpp b/src/USER-OMP/pair_edip_omp.cpp index d1fa4c1c7a..efba197153 100644 --- a/src/USER-OMP/pair_edip_omp.cpp +++ b/src/USER-OMP/pair_edip_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_edip_omp.h" #include "atom.h" @@ -50,7 +51,7 @@ void PairEDIPOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_eim_omp.cpp b/src/USER-OMP/pair_eim_omp.cpp index dd590b75e2..02b765a956 100644 --- a/src/USER-OMP/pair_eim_omp.cpp +++ b/src/USER-OMP/pair_eim_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include @@ -57,7 +58,7 @@ void PairEIMOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_gauss_cut_omp.cpp b/src/USER-OMP/pair_gauss_cut_omp.cpp index e14a85fc95..6d5344701d 100644 --- a/src/USER-OMP/pair_gauss_cut_omp.cpp +++ b/src/USER-OMP/pair_gauss_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_gauss_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairGaussCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_gauss_omp.cpp b/src/USER-OMP/pair_gauss_omp.cpp index de212c9213..106d520fa1 100644 --- a/src/USER-OMP/pair_gauss_omp.cpp +++ b/src/USER-OMP/pair_gauss_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_gauss_omp.h" #include "atom.h" @@ -45,7 +46,7 @@ void PairGaussOMP::compute(int eflag, int vflag) double occ = 0.0; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) reduction(+:occ) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) reduction(+:occ) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_gayberne_omp.cpp b/src/USER-OMP/pair_gayberne_omp.cpp index a58c16eafc..f0fd60a309 100644 --- a/src/USER-OMP/pair_gayberne_omp.cpp +++ b/src/USER-OMP/pair_gayberne_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_gayberne_omp.h" #include "math_extra.h" @@ -45,7 +46,7 @@ void PairGayBerneOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_gran_hertz_history_omp.cpp b/src/USER-OMP/pair_gran_hertz_history_omp.cpp index 1e3d86a1a5..9ad84afb92 100644 --- a/src/USER-OMP/pair_gran_hertz_history_omp.cpp +++ b/src/USER-OMP/pair_gran_hertz_history_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_gran_hertz_history_omp.h" #include "fix_neigh_history.h" @@ -69,7 +70,7 @@ void PairGranHertzHistoryOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_gran_hooke_history_omp.cpp b/src/USER-OMP/pair_gran_hooke_history_omp.cpp index d0e44cc430..3e519fc0d0 100644 --- a/src/USER-OMP/pair_gran_hooke_history_omp.cpp +++ b/src/USER-OMP/pair_gran_hooke_history_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "pair_gran_hooke_history_omp.h" @@ -70,7 +71,7 @@ void PairGranHookeHistoryOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_gran_hooke_omp.cpp b/src/USER-OMP/pair_gran_hooke_omp.cpp index 33296e22fa..8de959a91d 100644 --- a/src/USER-OMP/pair_gran_hooke_omp.cpp +++ b/src/USER-OMP/pair_gran_hooke_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_gran_hooke_omp.h" #include "atom.h" @@ -65,7 +66,7 @@ void PairGranHookeOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_hbond_dreiding_lj_omp.cpp b/src/USER-OMP/pair_hbond_dreiding_lj_omp.cpp index 77cc60e437..bb8bbcc984 100644 --- a/src/USER-OMP/pair_hbond_dreiding_lj_omp.cpp +++ b/src/USER-OMP/pair_hbond_dreiding_lj_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_hbond_dreiding_lj_omp.h" #include "atom.h" @@ -74,7 +75,7 @@ void PairHbondDreidingLJOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_hbond_dreiding_morse_omp.cpp b/src/USER-OMP/pair_hbond_dreiding_morse_omp.cpp index 47b2818be8..4ad3a8f057 100644 --- a/src/USER-OMP/pair_hbond_dreiding_morse_omp.cpp +++ b/src/USER-OMP/pair_hbond_dreiding_morse_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_hbond_dreiding_morse_omp.h" #include "atom.h" @@ -74,7 +75,7 @@ void PairHbondDreidingMorseOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj96_cut_omp.cpp b/src/USER-OMP/pair_lj96_cut_omp.cpp index b48946b3f9..adf0aac9b2 100644 --- a/src/USER-OMP/pair_lj96_cut_omp.cpp +++ b/src/USER-OMP/pair_lj96_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj96_cut_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairLJ96CutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_charmm_coul_charmm_implicit_omp.cpp b/src/USER-OMP/pair_lj_charmm_coul_charmm_implicit_omp.cpp index 10a253de6c..1c8e4c3e6b 100644 --- a/src/USER-OMP/pair_lj_charmm_coul_charmm_implicit_omp.cpp +++ b/src/USER-OMP/pair_lj_charmm_coul_charmm_implicit_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_charmm_coul_charmm_implicit_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJCharmmCoulCharmmImplicitOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_charmm_coul_charmm_omp.cpp b/src/USER-OMP/pair_lj_charmm_coul_charmm_omp.cpp index c4c5a9650e..55227e2e10 100644 --- a/src/USER-OMP/pair_lj_charmm_coul_charmm_omp.cpp +++ b/src/USER-OMP/pair_lj_charmm_coul_charmm_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_charmm_coul_charmm_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJCharmmCoulCharmmOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_charmm_coul_long_omp.cpp b/src/USER-OMP/pair_lj_charmm_coul_long_omp.cpp index 949ea3ded7..437bd183ed 100644 --- a/src/USER-OMP/pair_lj_charmm_coul_long_omp.cpp +++ b/src/USER-OMP/pair_lj_charmm_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_charmm_coul_long_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairLJCharmmCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_charmm_coul_long_soft_omp.cpp b/src/USER-OMP/pair_lj_charmm_coul_long_soft_omp.cpp index 2a41b0690b..b32f108098 100644 --- a/src/USER-OMP/pair_lj_charmm_coul_long_soft_omp.cpp +++ b/src/USER-OMP/pair_lj_charmm_coul_long_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_charmm_coul_long_soft_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairLJCharmmCoulLongSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_charmm_coul_msm_omp.cpp b/src/USER-OMP/pair_lj_charmm_coul_msm_omp.cpp index cecd27bfdc..9a0b44c1ec 100644 --- a/src/USER-OMP/pair_lj_charmm_coul_msm_omp.cpp +++ b/src/USER-OMP/pair_lj_charmm_coul_msm_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_charmm_coul_msm_omp.h" #include "atom.h" @@ -49,7 +50,7 @@ void PairLJCharmmCoulMSMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_class2_coul_cut_omp.cpp b/src/USER-OMP/pair_lj_class2_coul_cut_omp.cpp index 9e4dc08fd5..59a6841c9e 100644 --- a/src/USER-OMP/pair_lj_class2_coul_cut_omp.cpp +++ b/src/USER-OMP/pair_lj_class2_coul_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_class2_coul_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJClass2CoulCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_class2_coul_long_omp.cpp b/src/USER-OMP/pair_lj_class2_coul_long_omp.cpp index 4fd371e2eb..c0734e39d6 100644 --- a/src/USER-OMP/pair_lj_class2_coul_long_omp.cpp +++ b/src/USER-OMP/pair_lj_class2_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_class2_coul_long_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void PairLJClass2CoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_class2_omp.cpp b/src/USER-OMP/pair_lj_class2_omp.cpp index fa9b6ae703..2b91e10cfa 100644 --- a/src/USER-OMP/pair_lj_class2_omp.cpp +++ b/src/USER-OMP/pair_lj_class2_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_class2_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJClass2OMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cubic_omp.cpp b/src/USER-OMP/pair_lj_cubic_omp.cpp index 3fe6fab5de..778c25393d 100644 --- a/src/USER-OMP/pair_lj_cubic_omp.cpp +++ b/src/USER-OMP/pair_lj_cubic_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cubic_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairLJCubicOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_cut_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_cut_omp.cpp index 6c0a3706f7..d560b803f1 100644 --- a/src/USER-OMP/pair_lj_cut_coul_cut_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJCutCoulCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_cut_soft_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_cut_soft_omp.cpp index 742565d19c..1c88600e7a 100644 --- a/src/USER-OMP/pair_lj_cut_coul_cut_soft_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_cut_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_cut_soft_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJCutCoulCutSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_debye_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_debye_omp.cpp index 413758cc4a..79754e704b 100644 --- a/src/USER-OMP/pair_lj_cut_coul_debye_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_debye_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_debye_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJCutCoulDebyeOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_dsf_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_dsf_omp.cpp index 3295ede132..ec69a1a1ca 100644 --- a/src/USER-OMP/pair_lj_cut_coul_dsf_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_dsf_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_dsf_omp.h" #include "atom.h" @@ -53,7 +54,7 @@ void PairLJCutCoulDSFOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_long_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_long_omp.cpp index d32ec58607..618986389c 100644 --- a/src/USER-OMP/pair_lj_cut_coul_long_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_long_omp.h" #include "atom.h" @@ -52,7 +53,7 @@ void PairLJCutCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_long_soft_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_long_soft_omp.cpp index d1f97941f5..ce84ba01c3 100644 --- a/src/USER-OMP/pair_lj_cut_coul_long_soft_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_long_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_long_soft_omp.h" #include "atom.h" @@ -52,7 +53,7 @@ void PairLJCutCoulLongSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_msm_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_msm_omp.cpp index 9c48e03a13..58e5cee0c2 100644 --- a/src/USER-OMP/pair_lj_cut_coul_msm_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_msm_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_msm_omp.h" #include "atom.h" @@ -49,7 +50,7 @@ void PairLJCutCoulMSMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_coul_wolf_omp.cpp b/src/USER-OMP/pair_lj_cut_coul_wolf_omp.cpp index 09403b893c..4111c5b22c 100644 --- a/src/USER-OMP/pair_lj_cut_coul_wolf_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_coul_wolf_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_coul_wolf_omp.h" #include "atom.h" @@ -45,7 +46,7 @@ void PairLJCutCoulWolfOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_dipole_cut_omp.cpp b/src/USER-OMP/pair_lj_cut_dipole_cut_omp.cpp index c259b006c5..7d5d25c39b 100644 --- a/src/USER-OMP/pair_lj_cut_dipole_cut_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_dipole_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_dipole_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJCutDipoleCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_omp.cpp b/src/USER-OMP/pair_lj_cut_omp.cpp index f8670b7c28..3e7e92de21 100644 --- a/src/USER-OMP/pair_lj_cut_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairLJCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_soft_omp.cpp b/src/USER-OMP/pair_lj_cut_soft_omp.cpp index 988af13938..5064c4705e 100644 --- a/src/USER-OMP/pair_lj_cut_soft_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_soft_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairLJCutSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_thole_long_omp.cpp b/src/USER-OMP/pair_lj_cut_thole_long_omp.cpp index a8f2d2a081..72a7d5f16a 100644 --- a/src/USER-OMP/pair_lj_cut_thole_long_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_thole_long_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Paul Crozier (SNL) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_lj_cut_thole_long_omp.h" #include #include @@ -70,7 +71,7 @@ void PairLJCutTholeLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_tip4p_cut_omp.cpp b/src/USER-OMP/pair_lj_cut_tip4p_cut_omp.cpp index 40cfcb6bc2..2d1b828822 100644 --- a/src/USER-OMP/pair_lj_cut_tip4p_cut_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_tip4p_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_tip4p_cut_omp.h" #include "atom.h" @@ -93,7 +94,7 @@ void PairLJCutTIP4PCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_tip4p_long_omp.cpp b/src/USER-OMP/pair_lj_cut_tip4p_long_omp.cpp index d51382c0f1..a60f9d6a57 100644 --- a/src/USER-OMP/pair_lj_cut_tip4p_long_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_tip4p_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_lj_cut_tip4p_long_omp.h" #include #include "atom.h" @@ -93,7 +94,7 @@ void PairLJCutTIP4PLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_cut_tip4p_long_soft_omp.cpp b/src/USER-OMP/pair_lj_cut_tip4p_long_soft_omp.cpp index 350bea884d..f4a75b9af8 100644 --- a/src/USER-OMP/pair_lj_cut_tip4p_long_soft_omp.cpp +++ b/src/USER-OMP/pair_lj_cut_tip4p_long_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_cut_tip4p_long_soft_omp.h" #include "atom.h" @@ -93,7 +94,7 @@ void PairLJCutTIP4PLongSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_expand_omp.cpp b/src/USER-OMP/pair_lj_expand_omp.cpp index d3d1da263c..70b5e436fa 100644 --- a/src/USER-OMP/pair_lj_expand_omp.cpp +++ b/src/USER-OMP/pair_lj_expand_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_expand_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJExpandOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_gromacs_coul_gromacs_omp.cpp b/src/USER-OMP/pair_lj_gromacs_coul_gromacs_omp.cpp index 2fe7c39afe..0f0a8de2ff 100644 --- a/src/USER-OMP/pair_lj_gromacs_coul_gromacs_omp.cpp +++ b/src/USER-OMP/pair_lj_gromacs_coul_gromacs_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_gromacs_coul_gromacs_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJGromacsCoulGromacsOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_gromacs_omp.cpp b/src/USER-OMP/pair_lj_gromacs_omp.cpp index 4a4e68ec6e..ea2c9e8f55 100644 --- a/src/USER-OMP/pair_lj_gromacs_omp.cpp +++ b/src/USER-OMP/pair_lj_gromacs_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_gromacs_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJGromacsOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_long_coul_long_omp.cpp b/src/USER-OMP/pair_lj_long_coul_long_omp.cpp index 7286771c26..e74f487129 100644 --- a/src/USER-OMP/pair_lj_long_coul_long_omp.cpp +++ b/src/USER-OMP/pair_lj_long_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_long_coul_long_omp.h" #include "atom.h" @@ -56,7 +57,7 @@ void PairLJLongCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; @@ -318,7 +319,7 @@ void PairLJLongCoulLongOMP::compute_inner() const int nthreads = comm->nthreads; const int inum = list->inum_inner; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int ifrom, ito, tid; @@ -343,7 +344,7 @@ void PairLJLongCoulLongOMP::compute_middle() const int inum = list->inum_middle; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int ifrom, ito, tid; @@ -373,7 +374,7 @@ void PairLJLongCoulLongOMP::compute_outer(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp b/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp index d8eedc6c0b..9c8de110d7 100644 --- a/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp +++ b/src/USER-OMP/pair_lj_long_tip4p_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_long_tip4p_long_omp.h" #include "atom.h" @@ -96,7 +97,7 @@ void PairLJLongTIP4PLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; @@ -379,7 +380,7 @@ void PairLJLongTIP4PLongOMP::compute_inner() const int nthreads = comm->nthreads; const int inum = list->inum_inner; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int ifrom, ito, tid; @@ -404,7 +405,7 @@ void PairLJLongTIP4PLongOMP::compute_middle() const int inum = list->inum_middle; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int ifrom, ito, tid; @@ -458,7 +459,7 @@ void PairLJLongTIP4PLongOMP::compute_outer(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_sdk_coul_long_omp.cpp b/src/USER-OMP/pair_lj_sdk_coul_long_omp.cpp index 15fea32f53..4ad082cde1 100644 --- a/src/USER-OMP/pair_lj_sdk_coul_long_omp.cpp +++ b/src/USER-OMP/pair_lj_sdk_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_sdk_coul_long_omp.h" #include "atom.h" @@ -45,7 +46,7 @@ void PairLJSDKCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_sdk_coul_msm_omp.cpp b/src/USER-OMP/pair_lj_sdk_coul_msm_omp.cpp index 3326034da8..4871356b18 100644 --- a/src/USER-OMP/pair_lj_sdk_coul_msm_omp.cpp +++ b/src/USER-OMP/pair_lj_sdk_coul_msm_omp.cpp @@ -13,6 +13,7 @@ This style is a simplified re-implementation of the CG/CMM pair style ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_sdk_coul_msm_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void PairLJSDKCoulMSMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_sdk_omp.cpp b/src/USER-OMP/pair_lj_sdk_omp.cpp index 9ba90a2937..9f0671c61c 100644 --- a/src/USER-OMP/pair_lj_sdk_omp.cpp +++ b/src/USER-OMP/pair_lj_sdk_omp.cpp @@ -13,6 +13,7 @@ This style is a simplified re-implementation of the CG/CMM pair style ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_sdk_omp.h" #include "atom.h" @@ -47,7 +48,7 @@ void PairLJSDKOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_sf_dipole_sf_omp.cpp b/src/USER-OMP/pair_lj_sf_dipole_sf_omp.cpp index ca08f817dc..1adaf93953 100644 --- a/src/USER-OMP/pair_lj_sf_dipole_sf_omp.cpp +++ b/src/USER-OMP/pair_lj_sf_dipole_sf_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_sf_dipole_sf_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJSFDipoleSFOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_smooth_linear_omp.cpp b/src/USER-OMP/pair_lj_smooth_linear_omp.cpp index 0b29a8fc30..497c2c3a43 100644 --- a/src/USER-OMP/pair_lj_smooth_linear_omp.cpp +++ b/src/USER-OMP/pair_lj_smooth_linear_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_smooth_linear_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJSmoothLinearOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lj_smooth_omp.cpp b/src/USER-OMP/pair_lj_smooth_omp.cpp index fe3d64cbf6..bdb9b3141e 100644 --- a/src/USER-OMP/pair_lj_smooth_omp.cpp +++ b/src/USER-OMP/pair_lj_smooth_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lj_smooth_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairLJSmoothOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lubricate_omp.cpp b/src/USER-OMP/pair_lubricate_omp.cpp index dc6be0b96a..9db4239587 100644 --- a/src/USER-OMP/pair_lubricate_omp.cpp +++ b/src/USER-OMP/pair_lubricate_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_lubricate_omp.h" #include "atom.h" @@ -109,7 +110,7 @@ void PairLubricateOMP::compute(int eflag, int vflag) #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_lubricate_poly_omp.cpp b/src/USER-OMP/pair_lubricate_poly_omp.cpp index 648b10b114..dc143a3160 100644 --- a/src/USER-OMP/pair_lubricate_poly_omp.cpp +++ b/src/USER-OMP/pair_lubricate_poly_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pair_lubricate_poly_omp.h" #include #include "atom.h" @@ -106,7 +107,7 @@ void PairLubricatePolyOMP::compute(int eflag, int vflag) #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_meam_spline_omp.cpp b/src/USER-OMP/pair_meam_spline_omp.cpp index f4aff69881..19fb09dd7b 100644 --- a/src/USER-OMP/pair_meam_spline_omp.cpp +++ b/src/USER-OMP/pair_meam_spline_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include @@ -57,7 +58,7 @@ void PairMEAMSplineOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_morse_omp.cpp b/src/USER-OMP/pair_morse_omp.cpp index c77196d1c5..1f566dbd42 100644 --- a/src/USER-OMP/pair_morse_omp.cpp +++ b/src/USER-OMP/pair_morse_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_morse_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairMorseOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_morse_smooth_linear_omp.cpp b/src/USER-OMP/pair_morse_smooth_linear_omp.cpp index e30a774bf2..ac73344c67 100644 --- a/src/USER-OMP/pair_morse_smooth_linear_omp.cpp +++ b/src/USER-OMP/pair_morse_smooth_linear_omp.cpp @@ -13,6 +13,7 @@ Most code borrowed from pair_morse_omp.cpp ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_morse_smooth_linear_omp.h" #include "atom.h" @@ -47,7 +48,7 @@ void PairMorseSmoothLinearOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_nm_cut_coul_cut_omp.cpp b/src/USER-OMP/pair_nm_cut_coul_cut_omp.cpp index 7ffd189a5b..4326434450 100644 --- a/src/USER-OMP/pair_nm_cut_coul_cut_omp.cpp +++ b/src/USER-OMP/pair_nm_cut_coul_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_nm_cut_coul_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairNMCutCoulCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_nm_cut_coul_long_omp.cpp b/src/USER-OMP/pair_nm_cut_coul_long_omp.cpp index 0a0a861b6f..970b383f7e 100644 --- a/src/USER-OMP/pair_nm_cut_coul_long_omp.cpp +++ b/src/USER-OMP/pair_nm_cut_coul_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_nm_cut_coul_long_omp.h" #include "atom.h" @@ -51,7 +52,7 @@ void PairNMCutCoulLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_nm_cut_omp.cpp b/src/USER-OMP/pair_nm_cut_omp.cpp index cb74eed3f1..ef68071b68 100644 --- a/src/USER-OMP/pair_nm_cut_omp.cpp +++ b/src/USER-OMP/pair_nm_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_nm_cut_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairNMCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_peri_lps_omp.cpp b/src/USER-OMP/pair_peri_lps_omp.cpp index 3ea41321a7..cf29b5cab8 100644 --- a/src/USER-OMP/pair_peri_lps_omp.cpp +++ b/src/USER-OMP/pair_peri_lps_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "pair_peri_lps_omp.h" @@ -62,7 +63,7 @@ void PairPeriLPSOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_peri_pmb_omp.cpp b/src/USER-OMP/pair_peri_pmb_omp.cpp index 95e50df50d..1990b46fe5 100644 --- a/src/USER-OMP/pair_peri_pmb_omp.cpp +++ b/src/USER-OMP/pair_peri_pmb_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include #include "pair_peri_pmb_omp.h" @@ -58,7 +59,7 @@ void PairPeriPMBOMP::compute(int eflag, int vflag) } #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_resquared_omp.cpp b/src/USER-OMP/pair_resquared_omp.cpp index 65f1c7289f..557d212531 100644 --- a/src/USER-OMP/pair_resquared_omp.cpp +++ b/src/USER-OMP/pair_resquared_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_resquared_omp.h" #include "math_extra.h" @@ -45,7 +46,7 @@ void PairRESquaredOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_soft_omp.cpp b/src/USER-OMP/pair_soft_omp.cpp index 7de94a2cd1..85425974cc 100644 --- a/src/USER-OMP/pair_soft_omp.cpp +++ b/src/USER-OMP/pair_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_soft_omp.h" #include "atom.h" @@ -47,7 +48,7 @@ void PairSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_sw_omp.cpp b/src/USER-OMP/pair_sw_omp.cpp index 9812cf06ba..ebe501ff8e 100644 --- a/src/USER-OMP/pair_sw_omp.cpp +++ b/src/USER-OMP/pair_sw_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_sw_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairSWOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_table_omp.cpp b/src/USER-OMP/pair_table_omp.cpp index bf18d53d2e..2546bfdc9a 100644 --- a/src/USER-OMP/pair_table_omp.cpp +++ b/src/USER-OMP/pair_table_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_table_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairTableOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tersoff_mod_c_omp.cpp b/src/USER-OMP/pair_tersoff_mod_c_omp.cpp index 6b6b130c65..5e1e6b1b0e 100644 --- a/src/USER-OMP/pair_tersoff_mod_c_omp.cpp +++ b/src/USER-OMP/pair_tersoff_mod_c_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tersoff_mod_c_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairTersoffMODCOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tersoff_mod_omp.cpp b/src/USER-OMP/pair_tersoff_mod_omp.cpp index 634676ee49..aa90b88375 100644 --- a/src/USER-OMP/pair_tersoff_mod_omp.cpp +++ b/src/USER-OMP/pair_tersoff_mod_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tersoff_mod_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairTersoffMODOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tersoff_omp.cpp b/src/USER-OMP/pair_tersoff_omp.cpp index 9735ccaa1f..34dbfb73b6 100644 --- a/src/USER-OMP/pair_tersoff_omp.cpp +++ b/src/USER-OMP/pair_tersoff_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tersoff_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairTersoffOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tersoff_table_omp.cpp b/src/USER-OMP/pair_tersoff_table_omp.cpp index fa9512bf71..a0a7f4c810 100644 --- a/src/USER-OMP/pair_tersoff_table_omp.cpp +++ b/src/USER-OMP/pair_tersoff_table_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tersoff_table_omp.h" #include "atom.h" @@ -68,7 +69,7 @@ void PairTersoffTableOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tip4p_cut_omp.cpp b/src/USER-OMP/pair_tip4p_cut_omp.cpp index c8584b4fe3..5b983d3db5 100644 --- a/src/USER-OMP/pair_tip4p_cut_omp.cpp +++ b/src/USER-OMP/pair_tip4p_cut_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tip4p_cut_omp.h" #include "atom.h" @@ -92,7 +93,7 @@ void PairTIP4PCutOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tip4p_long_omp.cpp b/src/USER-OMP/pair_tip4p_long_omp.cpp index 89c3c17684..86bebdbeff 100644 --- a/src/USER-OMP/pair_tip4p_long_omp.cpp +++ b/src/USER-OMP/pair_tip4p_long_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tip4p_long_omp.h" #include "atom.h" @@ -93,7 +94,7 @@ void PairTIP4PLongOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_tip4p_long_soft_omp.cpp b/src/USER-OMP/pair_tip4p_long_soft_omp.cpp index 88da3d02a8..26e0420955 100644 --- a/src/USER-OMP/pair_tip4p_long_soft_omp.cpp +++ b/src/USER-OMP/pair_tip4p_long_soft_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_tip4p_long_soft_omp.h" #include "atom.h" @@ -93,7 +94,7 @@ void PairTIP4PLongSoftOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_ufm_omp.cpp b/src/USER-OMP/pair_ufm_omp.cpp index 23e76186c0..605d6dd2c6 100644 --- a/src/USER-OMP/pair_ufm_omp.cpp +++ b/src/USER-OMP/pair_ufm_omp.cpp @@ -14,6 +14,7 @@ Maurice de Koning (Unicamp/Brazil) - dekoning@ifi.unicamp.br ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_ufm_omp.h" #include "atom.h" @@ -45,7 +46,7 @@ void PairUFMOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_vashishta_omp.cpp b/src/USER-OMP/pair_vashishta_omp.cpp index a218ddf3ed..425a06c296 100644 --- a/src/USER-OMP/pair_vashishta_omp.cpp +++ b/src/USER-OMP/pair_vashishta_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_vashishta_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairVashishtaOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_vashishta_table_omp.cpp b/src/USER-OMP/pair_vashishta_table_omp.cpp index 0986128bf6..36c86a8995 100644 --- a/src/USER-OMP/pair_vashishta_table_omp.cpp +++ b/src/USER-OMP/pair_vashishta_table_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_vashishta_table_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairVashishtaTableOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_yukawa_colloid_omp.cpp b/src/USER-OMP/pair_yukawa_colloid_omp.cpp index 9b8428c648..e6ac3fa9fb 100644 --- a/src/USER-OMP/pair_yukawa_colloid_omp.cpp +++ b/src/USER-OMP/pair_yukawa_colloid_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_yukawa_colloid_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairYukawaColloidOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_yukawa_omp.cpp b/src/USER-OMP/pair_yukawa_omp.cpp index 20d557e605..f222876cb5 100644 --- a/src/USER-OMP/pair_yukawa_omp.cpp +++ b/src/USER-OMP/pair_yukawa_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_yukawa_omp.h" #include "atom.h" @@ -43,7 +44,7 @@ void PairYukawaOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pair_zbl_omp.cpp b/src/USER-OMP/pair_zbl_omp.cpp index 3a300ce477..284ebbf09c 100644 --- a/src/USER-OMP/pair_zbl_omp.cpp +++ b/src/USER-OMP/pair_zbl_omp.cpp @@ -12,6 +12,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include #include "pair_zbl_omp.h" #include "atom.h" @@ -44,7 +45,7 @@ void PairZBLOMP::compute(int eflag, int vflag) const int inum = list->inum; #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { int ifrom, ito, tid; diff --git a/src/USER-OMP/pppm_cg_omp.cpp b/src/USER-OMP/pppm_cg_omp.cpp index f9967bf52a..31098d2675 100644 --- a/src/USER-OMP/pppm_cg_omp.cpp +++ b/src/USER-OMP/pppm_cg_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pppm_cg_omp.h" #include #include @@ -59,7 +60,7 @@ PPPMCGOMP::PPPMCGOMP(LAMMPS *lmp) : PPPMCG(lmp), ThrOMP(lmp, THR_KSPACE) PPPMCGOMP::~PPPMCGOMP() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -81,7 +82,7 @@ void PPPMCGOMP::allocate() PPPMCG::allocate(); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -122,7 +123,7 @@ void PPPMCGOMP::compute_gf_ik() const int twoorder = 2*order; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double snx,sny,snz; @@ -216,7 +217,7 @@ void PPPMCGOMP::compute_gf_ad() double sf0=0.0,sf1=0.0,sf2=0.0,sf3=0.0,sf4=0.0,sf5=0.0; #if defined(_OPENMP) -#pragma omp parallel default(none) reduction(+:sf0,sf1,sf2,sf3,sf4,sf5) +#pragma omp parallel LMP_DEFAULT_NONE reduction(+:sf0,sf1,sf2,sf3,sf4,sf5) #endif { double snx,sny,snz,sqk; @@ -314,7 +315,7 @@ void PPPMCGOMP::compute(int eflag, int vflag) PPPMCG::compute(eflag,vflag); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) @@ -351,7 +352,7 @@ void PPPMCGOMP::make_rho() const int iy = nyhi_out - nylo_out + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const double * _noalias const q = atom->q; @@ -443,7 +444,7 @@ void PPPMCGOMP::fieldforce_ik() const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { FFT_SCALAR dx,dy,dz,x0,y0,z0,ekx,eky,ekz; @@ -524,7 +525,7 @@ void PPPMCGOMP::fieldforce_ad() const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { int i,ifrom,ito,tid,l,m,n,nx,ny,nz,mx,my,mz; @@ -617,7 +618,7 @@ void PPPMCGOMP::fieldforce_peratom() const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { FFT_SCALAR dx,dy,dz,x0,y0,z0; diff --git a/src/USER-OMP/pppm_disp_omp.cpp b/src/USER-OMP/pppm_disp_omp.cpp index 6b2c180a3f..aad77cffc7 100644 --- a/src/USER-OMP/pppm_disp_omp.cpp +++ b/src/USER-OMP/pppm_disp_omp.cpp @@ -16,6 +16,7 @@ Rolf Isele-Holder (RWTH Aachen University) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pppm_disp_omp.h" #include #include @@ -59,7 +60,7 @@ PPPMDispOMP::PPPMDispOMP(LAMMPS *lmp) : PPPMDisp(lmp), ThrOMP(lmp, THR_KSPACE) PPPMDispOMP::~PPPMDispOMP() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -87,7 +88,7 @@ void PPPMDispOMP::allocate() PPPMDisp::allocate(); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -114,7 +115,7 @@ void PPPMDispOMP::allocate() void PPPMDispOMP::compute_gf() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { @@ -204,7 +205,7 @@ void PPPMDispOMP::compute_gf() void PPPMDispOMP::compute_gf_6() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double *prd; @@ -311,7 +312,7 @@ void PPPMDispOMP::compute(int eflag, int vflag) PPPMDisp::compute(eflag,vflag); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) @@ -366,7 +367,7 @@ void PPPMDispOMP::particle_map(double dxinv, double dyinv, int flag = 0; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:flag) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:flag) schedule(static) #endif for (int i = 0; i < nlocal; i++) { @@ -419,7 +420,7 @@ void PPPMDispOMP::make_rho_c() const int iy = nyhi_out - nylo_out + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const double * _noalias const q = atom->q; @@ -509,7 +510,7 @@ void PPPMDispOMP::make_rho_g() const int iy = nyhi_out_6 - nylo_out_6 + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0]; @@ -613,7 +614,7 @@ void PPPMDispOMP::make_rho_a() const int iy = nyhi_out_6 - nylo_out_6 + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0]; @@ -723,7 +724,7 @@ void PPPMDispOMP::fieldforce_c_ik() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -828,7 +829,7 @@ void PPPMDispOMP::fieldforce_c_ad() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -935,7 +936,7 @@ void PPPMDispOMP::fieldforce_c_peratom() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1034,7 +1035,7 @@ void PPPMDispOMP::fieldforce_g_ik() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1138,7 +1139,7 @@ void PPPMDispOMP::fieldforce_g_ad() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1248,7 +1249,7 @@ void PPPMDispOMP::fieldforce_g_peratom() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1350,7 +1351,7 @@ void PPPMDispOMP::fieldforce_a_ik() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1486,7 +1487,7 @@ void PPPMDispOMP::fieldforce_a_ad() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1663,7 +1664,7 @@ void PPPMDispOMP::fieldforce_a_peratom() #if defined(_OPENMP) const int nthreads = comm->nthreads; -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) diff --git a/src/USER-OMP/pppm_disp_tip4p_omp.cpp b/src/USER-OMP/pppm_disp_tip4p_omp.cpp index ec294cd56d..7da4257e07 100644 --- a/src/USER-OMP/pppm_disp_tip4p_omp.cpp +++ b/src/USER-OMP/pppm_disp_tip4p_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pppm_disp_tip4p_omp.h" #include #include @@ -56,7 +57,7 @@ PPPMDispTIP4POMP::~PPPMDispTIP4POMP() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -84,7 +85,7 @@ void PPPMDispTIP4POMP::allocate() PPPMDispTIP4P::allocate(); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -111,7 +112,7 @@ void PPPMDispTIP4POMP::allocate() void PPPMDispTIP4POMP::compute_gf() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { @@ -198,7 +199,7 @@ void PPPMDispTIP4POMP::compute_gf() void PPPMDispTIP4POMP::compute_gf_6() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double *prd; @@ -302,7 +303,7 @@ void PPPMDispTIP4POMP::compute(int eflag, int vflag) PPPMDispTIP4P::compute(eflag,vflag); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) @@ -358,7 +359,7 @@ void PPPMDispTIP4POMP::particle_map_c(double dxinv, double dyinv, int flag = 0; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:flag) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:flag) schedule(static) #endif for (int i = 0; i < nlocal; i++) { dbl3_t xM; @@ -434,7 +435,7 @@ void PPPMDispTIP4POMP::particle_map(double dxinv, double dyinv, int flag = 0; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:flag) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:flag) schedule(static) #endif for (int i = 0; i < nlocal; i++) { @@ -487,7 +488,7 @@ void PPPMDispTIP4POMP::make_rho_c() const int iy = nyhi_out - nylo_out + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const double * _noalias const q = atom->q; @@ -582,7 +583,7 @@ void PPPMDispTIP4POMP::make_rho_g() const int iy = nyhi_out_6 - nylo_out_6 + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0]; @@ -684,7 +685,7 @@ void PPPMDispTIP4POMP::make_rho_a() const int iy = nyhi_out_6 - nylo_out_6 + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const dbl3_t * _noalias const x = (dbl3_t *) atom->x[0]; @@ -795,7 +796,7 @@ void PPPMDispTIP4POMP::fieldforce_c_ik() const double boxloz = boxlo[2]; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { dbl3_t xM; @@ -903,7 +904,7 @@ void PPPMDispTIP4POMP::fieldforce_c_ad() const double boxloz = boxlo[2]; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double s1,s2,s3,sf; @@ -1018,7 +1019,7 @@ void PPPMDispTIP4POMP::fieldforce_g_ik() const double * const * const x = atom->x; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1119,7 +1120,7 @@ void PPPMDispTIP4POMP::fieldforce_g_ad() const double hz_inv = nz_pppm_6/zprd_slab; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1226,7 +1227,7 @@ void PPPMDispTIP4POMP::fieldforce_g_peratom() const double * const * const x = atom->x; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1325,7 +1326,7 @@ void PPPMDispTIP4POMP::fieldforce_a_ik() const double * const * const x = atom->x; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1458,7 +1459,7 @@ void PPPMDispTIP4POMP::fieldforce_a_ad() const double hz_inv = nz_pppm_6/zprd_slab; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -1632,7 +1633,7 @@ void PPPMDispTIP4POMP::fieldforce_a_peratom() const double * const * const x = atom->x; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) diff --git a/src/USER-OMP/pppm_omp.cpp b/src/USER-OMP/pppm_omp.cpp index b9b39826ff..e3e46f4de0 100644 --- a/src/USER-OMP/pppm_omp.cpp +++ b/src/USER-OMP/pppm_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pppm_omp.h" #include #include @@ -61,7 +62,7 @@ void PPPMOMP::allocate() PPPM::allocate(); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -81,7 +82,7 @@ void PPPMOMP::allocate() PPPMOMP::~PPPMOMP() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -122,7 +123,7 @@ void PPPMOMP::compute_gf_ik() const int twoorder = 2*order; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double snx,sny,snz; @@ -216,7 +217,7 @@ void PPPMOMP::compute_gf_ad() double sf0=0.0,sf1=0.0,sf2=0.0,sf3=0.0,sf4=0.0,sf5=0.0; #if defined(_OPENMP) -#pragma omp parallel default(none) reduction(+:sf0,sf1,sf2,sf3,sf4,sf5) +#pragma omp parallel LMP_DEFAULT_NONE reduction(+:sf0,sf1,sf2,sf3,sf4,sf5) #endif { double snx,sny,snz,sqk; @@ -314,7 +315,7 @@ void PPPMOMP::compute(int eflag, int vflag) PPPM::compute(eflag,vflag); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) @@ -352,7 +353,7 @@ void PPPMOMP::make_rho() const int iy = nyhi_out - nylo_out + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const double * _noalias const q = atom->q; @@ -449,7 +450,7 @@ void PPPMOMP::fieldforce_ik() const double boxloz = boxlo[2]; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { FFT_SCALAR x0,y0,z0,ekx,eky,ekz; @@ -534,7 +535,7 @@ void PPPMOMP::fieldforce_ad() const double boxloz = boxlo[2]; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double s1,s2,s3,sf; @@ -627,7 +628,7 @@ void PPPMOMP::fieldforce_peratom() const double * _noalias const q = atom->q; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { FFT_SCALAR dx,dy,dz,x0,y0,z0; diff --git a/src/USER-OMP/pppm_tip4p_omp.cpp b/src/USER-OMP/pppm_tip4p_omp.cpp index 359b5dcc8d..6b3316943e 100644 --- a/src/USER-OMP/pppm_tip4p_omp.cpp +++ b/src/USER-OMP/pppm_tip4p_omp.cpp @@ -15,6 +15,7 @@ Contributing author: Axel Kohlmeyer (Temple U) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "pppm_tip4p_omp.h" #include #include @@ -61,7 +62,7 @@ PPPMTIP4POMP::PPPMTIP4POMP(LAMMPS *lmp) : PPPMTIP4POMP::~PPPMTIP4POMP() { #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -83,7 +84,7 @@ void PPPMTIP4POMP::allocate() PPPMTIP4P::allocate(); #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -124,7 +125,7 @@ void PPPMTIP4POMP::compute_gf_ik() const int twoorder = 2*order; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double snx,sny,snz; @@ -218,7 +219,7 @@ void PPPMTIP4POMP::compute_gf_ad() double sf0=0.0,sf1=0.0,sf2=0.0,sf3=0.0,sf4=0.0,sf5=0.0; #if defined(_OPENMP) -#pragma omp parallel default(none) reduction(+:sf0,sf1,sf2,sf3,sf4,sf5) +#pragma omp parallel LMP_DEFAULT_NONE reduction(+:sf0,sf1,sf2,sf3,sf4,sf5) #endif { double snx,sny,snz,sqk; @@ -316,7 +317,7 @@ void PPPMTIP4POMP::compute(int eflag, int vflag) PPPMTIP4P::compute(eflag,vflag); #if defined(_OPENMP) -#pragma omp parallel default(none) shared(eflag,vflag) +#pragma omp parallel LMP_DEFAULT_NONE LMP_SHARED(eflag,vflag) #endif { #if defined(_OPENMP) @@ -355,7 +356,7 @@ void PPPMTIP4POMP::particle_map() int flag = 0; #if defined(_OPENMP) -#pragma omp parallel for default(none) reduction(+:flag) schedule(static) +#pragma omp parallel for LMP_DEFAULT_NONE reduction(+:flag) schedule(static) #endif for (int i = 0; i < nlocal; i++) { dbl3_t xM; @@ -416,7 +417,7 @@ void PPPMTIP4POMP::make_rho() const int iy = nyhi_out - nylo_out + 1; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { const double * _noalias const q = atom->q; @@ -521,7 +522,7 @@ void PPPMTIP4POMP::fieldforce_ik() const double boxloz = boxlo[2]; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { dbl3_t xM; @@ -632,7 +633,7 @@ void PPPMTIP4POMP::fieldforce_ad() const double boxloz = boxlo[2]; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { double s1,s2,s3,sf; diff --git a/src/USER-OMP/reaxc_forces_omp.cpp b/src/USER-OMP/reaxc_forces_omp.cpp index e48a5c11d4..381b2e5525 100644 --- a/src/USER-OMP/reaxc_forces_omp.cpp +++ b/src/USER-OMP/reaxc_forces_omp.cpp @@ -26,6 +26,7 @@ . ----------------------------------------------------------------------*/ +#include "omp_compat.h" #include "reaxc_forces_omp.h" #include #include @@ -146,7 +147,7 @@ void Compute_Total_ForceOMP( reax_system *system, control_params *control, reax_list *bonds = (*lists) + BONDS; #if defined(_OPENMP) -#pragma omp parallel default(shared) //default(none) +#pragma omp parallel default(shared) //LMP_DEFAULT_NONE #endif { int i, j, k, pj, pk, start_j, end_j; diff --git a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp index d06966a92d..22d9df7702 100644 --- a/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp +++ b/src/USER-OMP/reaxc_hydrogen_bonds_omp.cpp @@ -26,6 +26,7 @@ . ----------------------------------------------------------------------*/ +#include "omp_compat.h" #include "reaxc_hydrogen_bonds_omp.h" #include #include @@ -57,7 +58,7 @@ void Hydrogen_BondsOMP( reax_system *system, control_params *control, const int nthreads = control->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(shared) //default(none) +#pragma omp parallel default(shared) //LMP_DEFAULT_NONE #endif { int i, j, k, pi, pk; diff --git a/src/USER-OMP/respa_omp.cpp b/src/USER-OMP/respa_omp.cpp index 5add419253..b5e5293aa4 100644 --- a/src/USER-OMP/respa_omp.cpp +++ b/src/USER-OMP/respa_omp.cpp @@ -15,6 +15,7 @@ Contributing authors: Mark Stevens (SNL), Paul Crozier (SNL) ------------------------------------------------------------------------- */ +#include "omp_compat.h" #include "respa_omp.h" #include "neighbor.h" #include "comm.h" @@ -146,7 +147,7 @@ void RespaOMP::setup(int flag) const int nall = atom->nlocal + atom->nghost; const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -241,7 +242,7 @@ void RespaOMP::setup_minimal(int flag) const int nall = atom->nlocal + atom->nghost; const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) @@ -394,7 +395,7 @@ void RespaOMP::recurse(int ilevel) const int nall = atom->nlocal + atom->nghost; const int nthreads = comm->nthreads; #if defined(_OPENMP) -#pragma omp parallel default(none) +#pragma omp parallel LMP_DEFAULT_NONE #endif { #if defined(_OPENMP) -- GitLab From 6563331d6e11da18a763143562a3b80b61ee9761 Mon Sep 17 00:00:00 2001 From: Michael Lamparski Date: Fri, 20 Mar 2020 13:21:21 -0400 Subject: [PATCH 060/577] rename to LAMMPS_OMP_COMPAT, improve docs --- cmake/CMakeLists.txt | 4 ++-- cmake/README.md | 10 ++++++++++ doc/src/Build_basics.rst | 3 ++- src/omp_compat.h | 2 +- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3dea0db8b0..60cbc8e5c0 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -242,9 +242,9 @@ if(BUILD_OMP) if ((CMAKE_CXX_COMPILER_ID STREQUAL "GNU") AND (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER 8.99.9)) # GCC 9.x strictly implements OpenMP 4.0 semantics for consts. - add_definitions(-DLMP_OMP_COMPAT=4) + add_definitions(-DLAMMPS_OMP_COMPAT=4) else() - add_definitions(-DLMP_OMP_COMPAT=3) + add_definitions(-DLAMMPS_OMP_COMPAT=3) endif() endif() diff --git a/cmake/README.md b/cmake/README.md index b9dd6d4373..cd90bc7020 100644 --- a/cmake/README.md +++ b/cmake/README.md @@ -264,6 +264,16 @@ cmake -C ../cmake/presets/all_on.cmake -C ../cmake/presets/nolib.cmake -D PKG_GP + + LAMMPS_OMP_COMPAT + Workaround for backwards-incompatible changes regarding predetermined sharing modes in OpenMP 4.x. A value of 3 or 4 should be used, reflecting the version of the OpenMP spec that is implemented by the compiler. + +
    +
    3 (default except for known OMP 4.0 compilers)
    +
    4
    +
    + + LAMMPS_MEMALIGN controls the alignment of blocks of memory allocated by LAMMPS diff --git a/doc/src/Build_basics.rst b/doc/src/Build_basics.rst index 96bc0f5bd1..62b16d9a03 100644 --- a/doc/src/Build_basics.rst +++ b/doc/src/Build_basics.rst @@ -147,7 +147,8 @@ semantics, which are incompatible with the OpenMP 3.1 semantics used in LAMMPS (for maximal compatibility with compiler versions in use). LAMMPS will try to detect compilers that use OpenMP 4.0 semantics and change the directives accordingly, but if your compiler is not -detected, you may set the CMake variable ``-D LMP_OMP_COMPAT=4``. +detected, you may set the define ``-D LAMMPS_OMP_COMPAT=4`` in ``LMP_INC`` +or the CMake build command. ---------- diff --git a/src/omp_compat.h b/src/omp_compat.h index 8abf1c54bc..add429eea8 100644 --- a/src/omp_compat.h +++ b/src/omp_compat.h @@ -25,7 +25,7 @@ // so this is what LAMMPS primarily uses. For those compilers // that strictly implement OpenMP 4.0 (such as GCC 9.0), we // give up default(none). -#if LMP_OMP_COMPAT == 4 +#if LAMMPS_OMP_COMPAT == 4 # define LMP_SHARED(...) # define LMP_DEFAULT_NONE default(shared) #else -- GitLab From 62cb760ee2ea8172f621201f04417c9d60bf9474 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 14:42:29 -0600 Subject: [PATCH 061/577] cmake: remove LIB_SOURCES and LMP_SOURCES --- cmake/CMakeLists.txt | 30 ++++++++++++------------- cmake/Modules/Packages/CORESHELL.cmake | 2 +- cmake/Modules/Packages/GPU.cmake | 2 +- cmake/Modules/Packages/KOKKOS.cmake | 2 +- cmake/Modules/Packages/OPT.cmake | 2 +- cmake/Modules/Packages/QEQ.cmake | 2 +- cmake/Modules/Packages/USER-INTEL.cmake | 2 +- cmake/Modules/Packages/USER-OMP.cmake | 2 +- cmake/Modules/Packages/USER-SDPD.cmake | 4 +++- 9 files changed, 25 insertions(+), 23 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 4dd079eaae..eb5700b19d 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -21,11 +21,6 @@ if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX "$ENV{HOME}/.local" CACHE PATH "default install path" FORCE ) endif() -# To avoid conflicts with the conventional Makefile build system, we build everything here -file(GLOB LIB_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) -file(GLOB LMP_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) -list(REMOVE_ITEM LIB_SOURCES ${LMP_SOURCES}) - # Cmake modules/macros are in a subdirectory to keep this file cleaner set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules) @@ -110,8 +105,19 @@ endif() option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF) -if(NOT BUILD_EXE AND NOT BUILD_LIB) - message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") +if(BUILD_LIB) + file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) + list(REMOVE_ITEM ALL_SOURCES ${MAIN_SOURCES}) + add_library(lammps ${ALL_SOURCES}) + if(BUILD_EXE) + add_executable(lmp ${MAIN_SOURCES}) + target_link_libraries(lmp PRIVATE lammps) + endif() +else() + if(NOT BUILD_EXE) + message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") + endif() + add_executable(lammps ${ALL_SOURCES}) endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) @@ -391,7 +397,7 @@ foreach(PKG ${DEFAULT_PACKAGES}) # detects styles in package and adds them to global list RegisterStyles(${${PKG}_SOURCES_DIR}) - list(APPEND LIB_SOURCES ${${PKG}_SOURCES}) + target_sources(lammps PRIVATE ${${PKG}_SOURCES}) include_directories(${${PKG}_SOURCES_DIR}) endif() @@ -533,7 +539,6 @@ if (${_index} GREATER -1) endif() list(REMOVE_DUPLICATES LAMMPS_LINK_LIBS) if(BUILD_LIB) - add_library(lammps ${LIB_SOURCES}) target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(lammps ${LAMMPS_DEPS}) @@ -579,15 +584,10 @@ if(BUILD_LIB) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) configure_file(FindLAMMPS.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Modules) -else() - list(APPEND LMP_SOURCES ${LIB_SOURCES}) endif() if(BUILD_EXE) - add_executable(lmp ${LMP_SOURCES}) - if(BUILD_LIB) - target_link_libraries(lmp lammps) - else() + if(NOT BUILD_LIB) target_link_libraries(lmp ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(lmp ${LAMMPS_DEPS}) diff --git a/cmake/Modules/Packages/CORESHELL.cmake b/cmake/Modules/Packages/CORESHELL.cmake index 591477c899..2afe2b8c1b 100644 --- a/cmake/Modules/Packages/CORESHELL.cmake +++ b/cmake/Modules/Packages/CORESHELL.cmake @@ -8,6 +8,6 @@ if(PKG_CORESHELL) get_property(CORESHELL_SOURCES GLOBAL PROPERTY CORESHELL_SOURCES) - list(APPEND LIB_SOURCES ${CORESHELL_SOURCES}) + target_sources(lammps PRIVATE ${CORESHELL_SOURCES}) include_directories(${CORESHELL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index abbcb1f495..e8ca4d35ab 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -192,6 +192,6 @@ if(PKG_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) - list(APPEND LIB_SOURCES ${GPU_SOURCES}) + target_sources(lammps PRIVATE ${GPU_SOURCES}) include_directories(${GPU_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 29beaca957..4b871ccb46 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -69,6 +69,6 @@ if(PKG_KOKKOS) get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) - list(APPEND LIB_SOURCES ${KOKKOS_PKG_SOURCES}) + target_sources(lammps PRIVATE ${KOKKOS_PKG_SOURCES}) include_directories(${KOKKOS_PKG_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/OPT.cmake b/cmake/Modules/Packages/OPT.cmake index f2802c757b..02e3877c59 100644 --- a/cmake/Modules/Packages/OPT.cmake +++ b/cmake/Modules/Packages/OPT.cmake @@ -8,6 +8,6 @@ if(PKG_OPT) get_property(OPT_SOURCES GLOBAL PROPERTY OPT_SOURCES) - list(APPEND LIB_SOURCES ${OPT_SOURCES}) + target_sources(lammps PRIVATE ${OPT_SOURCES}) include_directories(${OPT_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/QEQ.cmake b/cmake/Modules/Packages/QEQ.cmake index 94cca30540..9b151c2610 100644 --- a/cmake/Modules/Packages/QEQ.cmake +++ b/cmake/Modules/Packages/QEQ.cmake @@ -15,6 +15,6 @@ if(PKG_QEQ) endforeach() get_property(QEQ_SOURCES GLOBAL PROPERTY QEQ_SOURCES) - list(APPEND LIB_SOURCES ${QEQ_SOURCES}) + target_sources(lammps PRIVATE ${QEQ_SOURCES}) include_directories(${QEQ_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index d0941a0a12..7b08a7b459 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -108,6 +108,6 @@ if(PKG_USER-INTEL) RegisterIntegrateStyle(${USER-INTEL_SOURCES_DIR}/verlet_lrt_intel.h) endif() - list(APPEND LIB_SOURCES ${USER-INTEL_SOURCES}) + target_sources(lammps PRIVATE ${USER-INTEL_SOURCES}) include_directories(${USER-INTEL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-OMP.cmake b/cmake/Modules/Packages/USER-OMP.cmake index 668f42f10a..4b1a4b1571 100644 --- a/cmake/Modules/Packages/USER-OMP.cmake +++ b/cmake/Modules/Packages/USER-OMP.cmake @@ -37,6 +37,6 @@ if(PKG_USER-OMP) ${USER-OMP_SOURCES_DIR}/reaxc_valence_angles_omp.cpp) endif() - list(APPEND LIB_SOURCES ${USER-OMP_SOURCES}) + target_sources(lammps PRIVATE ${USER-OMP_SOURCES}) include_directories(${USER-OMP_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-SDPD.cmake b/cmake/Modules/Packages/USER-SDPD.cmake index 530dcf2bd9..1105fbd7ce 100644 --- a/cmake/Modules/Packages/USER-SDPD.cmake +++ b/cmake/Modules/Packages/USER-SDPD.cmake @@ -5,7 +5,9 @@ if(PKG_USER-SDPD) get_property(hlist GLOBAL PROPERTY FIX) if(NOT PKG_RIGID) list(REMOVE_ITEM hlist ${USER-SDPD_SOURCES_DIR}/fix_rigid_meso.h) - list(REMOVE_ITEM LIB_SOURCES ${USER-SDPD_SOURCES_DIR}/fix_rigid_meso.cpp) + get_target_property(LAMMPS_SOURCES lammps SOURCES) + list(REMOVE_ITEM LAMMPS_SOURCES ${USER-SDPD_SOURCES_DIR}/fix_rigid_meso.cpp) + set_property(TARGET lammps PROPERTY SOURCES ${LAMMPS_SOURCES}) endif() set_property(GLOBAL PROPERTY FIX "${hlist}") -- GitLab From cd89a7c4b7edb877694e07a91edc558a94845f12 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 18:03:07 -0600 Subject: [PATCH 062/577] cmake: fix renamed target for exe --- cmake/CMakeLists.txt | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index eb5700b19d..0fae7f55bf 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -105,12 +105,14 @@ endif() option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF) +file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) if(BUILD_LIB) file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) list(REMOVE_ITEM ALL_SOURCES ${MAIN_SOURCES}) add_library(lammps ${ALL_SOURCES}) if(BUILD_EXE) add_executable(lmp ${MAIN_SOURCES}) + set(LAMMPS_EXE lmp) target_link_libraries(lmp PRIVATE lammps) endif() else() @@ -118,6 +120,7 @@ else() message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") endif() add_executable(lammps ${ALL_SOURCES}) + set(LAMMPS_EXE lammps) endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) @@ -588,14 +591,14 @@ endif() if(BUILD_EXE) if(NOT BUILD_LIB) - target_link_libraries(lmp ${LAMMPS_LINK_LIBS}) + target_link_libraries(${LAMMPS_EXE} ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) - add_dependencies(lmp ${LAMMPS_DEPS}) + add_dependencies(${LAMMPS_EXE} ${LAMMPS_DEPS}) endif() endif() - set_target_properties(lmp PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) - install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) + set_target_properties(${LAMMPS_EXE} PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) + install(TARGETS ${LAMMPS_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1) endif() -- GitLab From 5828815b3ec50845be1a312056de559c05bbff1a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 18:55:53 -0600 Subject: [PATCH 063/577] cmake: remove LAMMPS_LINK_LIBS --- cmake/CMakeLists.txt | 28 ++++++---------- cmake/Modules/Packages/COMPRESS.cmake | 3 +- cmake/Modules/Packages/GPU.cmake | 4 +-- cmake/Modules/Packages/KIM.cmake | 5 ++- cmake/Modules/Packages/KOKKOS.cmake | 6 ++-- cmake/Modules/Packages/KSPACE.cmake | 6 ++-- cmake/Modules/Packages/LATTE.cmake | 2 +- cmake/Modules/Packages/MESSAGE.cmake | 2 +- cmake/Modules/Packages/MSCG.cmake | 2 +- cmake/Modules/Packages/PYTHON.cmake | 2 +- cmake/Modules/Packages/USER-COLVARS.cmake | 4 +-- cmake/Modules/Packages/USER-INTEL.cmake | 6 ++-- cmake/Modules/Packages/USER-MOLFILE.cmake | 2 +- cmake/Modules/Packages/USER-NETCDF.cmake | 4 +-- cmake/Modules/Packages/USER-PLUMED.cmake | 8 ++--- cmake/Modules/Packages/USER-QMMM.cmake | 2 +- cmake/Modules/Packages/USER-QUIP.cmake | 2 +- cmake/Modules/Packages/USER-SCAFACOS.cmake | 38 +++++++++++----------- cmake/Modules/Packages/USER-VTK.cmake | 2 +- cmake/Modules/Packages/VORONOI.cmake | 2 +- 20 files changed, 60 insertions(+), 70 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0fae7f55bf..9190374a2e 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -126,7 +126,6 @@ endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) include(GNUInstallDirs) -set(LAMMPS_LINK_LIBS) set(LAMMPS_DEPS) set(LAMMPS_API_DEFINES) @@ -173,7 +172,7 @@ if(PKG_USER-ADIOS) # script that defines the MPI::MPI_C target enable_language(C) find_package(ADIOS2 REQUIRED) - list(APPEND LAMMPS_LINK_LIBS adios2::adios2) + target_link_libraries(lammps PRIVATE adios2::adios2) endif() # do MPI detection after language activation, @@ -188,9 +187,8 @@ if(BUILD_MPI) include(MPI4WIN) else() find_package(MPI REQUIRED) - include_directories(${MPI_CXX_INCLUDE_PATH}) add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) - list(APPEND LAMMPS_LINK_LIBS ${MPI_CXX_LIBRARIES}) + target_link_libraries(lammps PRIVATE MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) if(LAMMPS_LONGLONG_TO_LONG) add_definitions(-DLAMMPS_LONGLONG_TO_LONG) @@ -201,7 +199,7 @@ else() file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) add_library(mpi_stubs STATIC ${MPI_SOURCES}) include_directories(${LAMMPS_SOURCE_DIR}/STUBS) - list(APPEND LAMMPS_LINK_LIBS mpi_stubs) + target_link_libraries(lammps PRIVATE mpi_stubs) endif() set(LAMMPS_SIZES "smallbig" CACHE STRING "LAMMPS integer sizes (smallsmall: all 32-bit, smallbig: 64-bit #atoms #timesteps, bigbig: also 64-bit imageint, 64-bit atom ids)") @@ -284,8 +282,7 @@ option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND}) if(WITH_JPEG) find_package(JPEG REQUIRED) add_definitions(-DLAMMPS_JPEG) - include_directories(${JPEG_INCLUDE_DIR}) - list(APPEND LAMMPS_LINK_LIBS ${JPEG_LIBRARIES}) + target_link_libraries(lammps PRIVATE JPEG::JPEG) endif() find_package(PNG QUIET) @@ -298,8 +295,7 @@ endif() if(WITH_PNG) find_package(PNG REQUIRED) find_package(ZLIB REQUIRED) - include_directories(${PNG_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${PNG_LIBRARIES} ${ZLIB_LIBRARIES}) + target_link_libraries(lammps PRIVATE PNG::PNG ZLIB::ZLIB) add_definitions(-DLAMMPS_PNG) endif() @@ -376,7 +372,7 @@ include(CheckLibraryExists) # message(FATAL_ERROR "Could not find needed math function - ${FUNC}") # endif(NOT FOUND_${FUNC}_${MATH_LIBRARIES}) #endforeach(FUNC) -list(APPEND LAMMPS_LINK_LIBS ${MATH_LIBRARIES}) +target_link_libraries(lammps PRIVATE ${MATH_LIBRARIES}) ###################################### # Generate Basic Style files @@ -442,7 +438,7 @@ foreach(SIMPLE_LIB POEMS USER-ATC USER-AWPMD USER-H5MD) if(LAMMPS_USE_MPI4WIN) add_dependencies(${PKG_LIB} mpi4win_build) endif() - list(APPEND LAMMPS_LINK_LIBS ${PKG_LIB}) + target_link_libraries(lammps PRIVATE ${PKG_LIB}) if(PKG_LIB STREQUAL awpmd) target_include_directories(awpmd PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/awpmd/systems/interact ${LAMMPS_LIB_SOURCE_DIR}/awpmd/ivutils/include) elseif(PKG_LIB STREQUAL h5md) @@ -486,9 +482,9 @@ include(Packages/GPU) ###################################################################### if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if(LAMMPS_USE_MPI4WIN) - list(APPEND LAMMPS_LINK_LIBS ${MPI4WIN_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MPI4WIN_LIBRARIES}) endif() - list(APPEND LAMMPS_LINK_LIBS -lwsock32 -lpsapi) + target_link_libraries(lammps PRIVATE -lwsock32 -lpsapi) endif() ###################################################### @@ -538,11 +534,9 @@ list(APPEND LAMMPS_DEPS gitversion) get_property(LANGUAGES GLOBAL PROPERTY ENABLED_LANGUAGES) list (FIND LANGUAGES "Fortran" _index) if (${_index} GREATER -1) - list(APPEND LAMMPS_LINK_LIBS ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() -list(REMOVE_DUPLICATES LAMMPS_LINK_LIBS) if(BUILD_LIB) - target_link_libraries(lammps ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(lammps ${LAMMPS_DEPS}) endif() @@ -591,7 +585,6 @@ endif() if(BUILD_EXE) if(NOT BUILD_LIB) - target_link_libraries(${LAMMPS_EXE} ${LAMMPS_LINK_LIBS}) if(LAMMPS_DEPS) add_dependencies(${LAMMPS_EXE} ${LAMMPS_DEPS}) endif() @@ -736,7 +729,6 @@ if(BUILD_SHARED_LIBS) else() message(STATUS "Static library flags: ${CMAKE_STATIC_LINKER_FLAGS}") endif() -message(STATUS "Link libraries: ${LAMMPS_LINK_LIBS}") if(BUILD_MPI) message(STATUS "Using MPI with headers in ${MPI_CXX_INCLUDE_PATH} and these libraries: ${MPI_CXX_LIBRARIES};${MPI_Fortran_LIBRARIES}") endif() diff --git a/cmake/Modules/Packages/COMPRESS.cmake b/cmake/Modules/Packages/COMPRESS.cmake index 864b868865..ea5d5e37bd 100644 --- a/cmake/Modules/Packages/COMPRESS.cmake +++ b/cmake/Modules/Packages/COMPRESS.cmake @@ -1,5 +1,4 @@ if(PKG_COMPRESS) find_package(ZLIB REQUIRED) - include_directories(${ZLIB_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${ZLIB_LIBRARIES}) + target_link_libraries(lammps PRIVATE ZLIB::ZLIB) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index e8ca4d35ab..427644f9c7 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -107,7 +107,7 @@ if(PKG_GPU) target_compile_definitions(gpu PRIVATE -DUSE_CUDPP) endif() - list(APPEND LAMMPS_LINK_LIBS gpu) + target_link_libraries(lammps PRIVATE gpu) if(LAMMPS_USE_MPI4WIN) add_dependencies(gpu mpi4win_build) endif() @@ -171,7 +171,7 @@ if(PKG_GPU) target_compile_definitions(gpu PRIVATE -D_${GPU_PREC_SETTING} -D${OCL_TUNE}_OCL -DMPI_GERYON -DUCL_NO_EXIT) target_compile_definitions(gpu PRIVATE -DUSE_OPENCL) - list(APPEND LAMMPS_LINK_LIBS gpu) + target_link_libraries(lammps PRIVATE gpu) if(LAMMPS_USE_MPI4WIN) add_dependencies(gpu mpi4win_build) endif() diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 617068ce13..002fbbcaed 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -2,8 +2,7 @@ if(PKG_KIM) set(KIM-API_MIN_VERSION 2.1) find_package(CURL) if(CURL_FOUND) - include_directories(${CURL_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${CURL_LIBRARIES}) + target_link_libraries(lammps PRIVATE CURL::libcurl) add_definitions(-DLMP_KIM_CURL) set(LMP_DEBUG_CURL OFF CACHE STRING "Set libcurl verbose mode on/off. If on, it displays a lot of verbose information about its operations.") mark_as_advanced(LMP_DEBUG_CURL) @@ -62,6 +61,6 @@ if(PKG_KIM) else() find_package(KIM-API ${KIM-API_MIN_VERSION} REQUIRED) endif() - list(APPEND LAMMPS_LINK_LIBS "${KIM-API_LDFLAGS}") + target_link_libraries(lammps PRIVATE "${KIM-API_LDFLAGS}") include_directories(${KIM-API_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 4b871ccb46..58d2c139f6 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -5,7 +5,7 @@ if(PKG_KOKKOS) option(EXTERNAL_KOKKOS "Build against external kokkos library") if(EXTERNAL_KOKKOS) find_package(Kokkos REQUIRED) - list(APPEND LAMMPS_LINK_LIBS Kokkos::kokkos) + target_link_libraries(lammps PRIVATE Kokkos::kokkos) else() set(LAMMPS_LIB_KOKKOS_SRC_DIR ${LAMMPS_LIB_SOURCE_DIR}/kokkos) set(LAMMPS_LIB_KOKKOS_BIN_DIR ${LAMMPS_LIB_BINARY_DIR}/kokkos) @@ -16,7 +16,7 @@ if(PKG_KOKKOS) ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src ${LAMMPS_LIB_KOKKOS_BIN_DIR}) include_directories(${Kokkos_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS kokkos) + target_link_libraries(lammps PRIVATE kokkos) endif() add_definitions(-DLMP_KOKKOS) @@ -45,7 +45,7 @@ if(PKG_KOKKOS) if(KOKKOS_ENABLE_CUDA) if(NOT ${FFT} STREQUAL "KISS") add_definitions(-DFFT_CUFFT) - list(APPEND LAMMPS_LINK_LIBS cufft) + target_link_libraries(lammps PRIVATE cufft) endif() endif() endif() diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index 07612447f9..4f92a6963c 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -20,7 +20,7 @@ if(PKG_KSPACE) find_package(${FFTW} REQUIRED) add_definitions(-DFFT_FFTW3) include_directories(${${FFTW}_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${${FFTW}_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${${FFTW}_LIBRARIES}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) else() @@ -30,7 +30,7 @@ if(PKG_KSPACE) if(FFT_FFTW_THREADS) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) add_definitions(-DFFT_FFTW_THREADS) - list(APPEND LAMMPS_LINK_LIBS ${${FFTW}_OMP_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${${FFTW}_OMP_LIBRARIES}) else() message(FATAL_ERROR "Need OpenMP enabled FFTW3 library for FFT_THREADS") endif() @@ -43,7 +43,7 @@ if(PKG_KSPACE) add_definitions(-DFFT_MKL_THREADS) endif() include_directories(${MKL_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${MKL_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() # last option is KISSFFT add_definitions(-DFFT_KISS) diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index 9f665d7f0e..55d9b31797 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -36,5 +36,5 @@ if(PKG_LATTE) if(NOT LAPACK_FOUND) add_dependencies(latte_build linalg) endif() - list(APPEND LAMMPS_LINK_LIBS ${LATTE_LIBRARIES} ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${LATTE_LIBRARIES} ${LAPACK_LIBRARIES}) endif() diff --git a/cmake/Modules/Packages/MESSAGE.cmake b/cmake/Modules/Packages/MESSAGE.cmake index aff9c2964a..c28c50c507 100644 --- a/cmake/Modules/Packages/MESSAGE.cmake +++ b/cmake/Modules/Packages/MESSAGE.cmake @@ -27,6 +27,6 @@ if(PKG_MESSAGE) target_include_directories(cslib PRIVATE ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src/STUBS_ZMQ) endif() - list(APPEND LAMMPS_LINK_LIBS cslib) + target_link_libraries(lammps PRIVATE cslib) include_directories(${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src) endif() diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 35f0c57449..e300ed6ae2 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -43,6 +43,6 @@ if(PKG_MSCG) message(FATAL_ERROR "MSCG not found, help CMake to find it by setting MSCG_LIBRARY and MSCG_INCLUDE_DIRS, or set DOWNLOAD_MSCG=ON to download it") endif() endif() - list(APPEND LAMMPS_LINK_LIBS ${MSCG_LIBRARIES} ${GSL_LIBRARIES} ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MSCG_LIBRARIES} GSL::gsl ${LAPACK_LIBRARIES}) include_directories(${MSCG_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index 4f8959ae38..7d6e2999f7 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -2,5 +2,5 @@ if(PKG_PYTHON) find_package(PythonLibs REQUIRED) add_definitions(-DLMP_PYTHON) include_directories(${PYTHON_INCLUDE_DIR}) - list(APPEND LAMMPS_LINK_LIBS ${PYTHON_LIBRARY}) + target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARY}) endif() diff --git a/cmake/Modules/Packages/USER-COLVARS.cmake b/cmake/Modules/Packages/USER-COLVARS.cmake index a112fbb6aa..2a337b9c8b 100644 --- a/cmake/Modules/Packages/USER-COLVARS.cmake +++ b/cmake/Modules/Packages/USER-COLVARS.cmake @@ -16,10 +16,10 @@ if(PKG_USER-COLVARS) add_library(colvars STATIC ${COLVARS_SOURCES}) target_include_directories(colvars PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/colvars) - list(APPEND LAMMPS_LINK_LIBS colvars) + target_link_libraries(lammps PRIVATE colvars) if(COLVARS_LEPTON) - list(APPEND LAMMPS_LINK_LIBS lepton) + target_link_libraries(lammps PRIVATE lepton) target_compile_options(colvars PRIVATE -DLEPTON) target_include_directories(colvars PUBLIC ${LEPTON_DIR}/include) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 7b08a7b459..0a9b634bc7 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -25,7 +25,7 @@ if(PKG_USER-INTEL) if(INTEL_LRT_MODE STREQUAL "THREADS") if(Threads_FOUND) add_definitions(-DLMP_INTEL_USELRT) - list(APPEND LAMMPS_LINK_LIBS ${CMAKE_THREAD_LIBS_INIT}) + target_link_libraries(lammps PRIVATE Threads::Threads) else() message(FATAL_ERROR "Must have working threads library for Long-range thread support") endif() @@ -44,7 +44,7 @@ if(PKG_USER-INTEL) find_package(TBB QUIET) if(TBB_FOUND) - list(APPEND LAMMPS_LINK_LIBS ${TBB_MALLOC_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${TBB_MALLOC_LIBRARIES}) else() add_definitions(-DLMP_INTEL_NO_TBB) if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") @@ -55,7 +55,7 @@ if(PKG_USER-INTEL) find_package(MKL QUIET) if(MKL_FOUND) add_definitions(-DLMP_USE_MKL_RNG) - list(APPEND LAMMPS_LINK_LIBS ${MKL_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() message(STATUS "Pair style dpd/intel will be faster with MKL libraries") endif() diff --git a/cmake/Modules/Packages/USER-MOLFILE.cmake b/cmake/Modules/Packages/USER-MOLFILE.cmake index 16ffc34994..cbba1eee7b 100644 --- a/cmake/Modules/Packages/USER-MOLFILE.cmake +++ b/cmake/Modules/Packages/USER-MOLFILE.cmake @@ -6,5 +6,5 @@ if(PKG_USER-MOLFILE) if(NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") target_link_libraries(molfile INTERFACE ${CMAKE_DL_LIBS}) endif() - list(APPEND LAMMPS_LINK_LIBS molfile) + target_link_libraries(lammps PRIVATE molfile) endif() diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index 921156f1e0..8d62f5f7ec 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -10,13 +10,13 @@ if(PKG_USER-NETCDF) if(NETCDF_FOUND) include_directories(${NETCDF_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${NETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${NETCDF_LIBRARIES}) add_definitions(-DLMP_HAS_NETCDF) endif(NETCDF_FOUND) if(PNETCDF_FOUND) include_directories(${PNETCDF_INCLUDES}) - list(APPEND LAMMPS_LINK_LIBS ${PNETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${PNETCDF_LIBRARIES}) add_definitions(-DLMP_HAS_PNETCDF) endif(PNETCDF_FOUND) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index 426ae2df2a..9669f1955c 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -70,12 +70,12 @@ if(PKG_USER-PLUMED) list(APPEND LAMMPS_DEPS plumed_build) if(PLUMED_MODE STREQUAL "STATIC") add_definitions(-D__PLUMED_WRAPPER_CXX=1) - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) + target_link_libraries(lammps ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "SHARED") - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) + target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "RUNTIME") add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_INSTALL_DIR}/lib/libplumedWrapper.a -rdynamic ${CMAKE_DL_LIBS}) + target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumedWrapper.a -rdynamic ${CMAKE_DL_LIBS}) endif() set(PLUMED_INCLUDE_DIRS "${PLUMED_INSTALL_DIR}/include") else() @@ -90,7 +90,7 @@ if(PKG_USER-PLUMED) add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_LIBDIR}/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.runtime) endif() - list(APPEND LAMMPS_LINK_LIBS ${PLUMED_LOAD}) + target_link_libraries(lammps PRIVATE ${PLUMED_LOAD}) endif() include_directories(${PLUMED_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-QMMM.cmake b/cmake/Modules/Packages/USER-QMMM.cmake index 544455868e..0f3fa93b2a 100644 --- a/cmake/Modules/Packages/USER-QMMM.cmake +++ b/cmake/Modules/Packages/USER-QMMM.cmake @@ -8,6 +8,6 @@ if(PKG_USER-QMMM) message(WARNING "It is recommended to use BUILD_SHARED_LIBS=yes with USER-QMMM") endif() add_library(qmmm STATIC ${LAMMPS_LIB_SOURCE_DIR}/qmmm/libqmmm.c) - list(APPEND LAMMPS_LINK_LIBS qmmm) + target_link_libraries(lammps PRIVATE qmmm) target_include_directories(qmmm PUBLIC ${LAMMPS_LIB_SOURCE_DIR}/qmmm) endif() diff --git a/cmake/Modules/Packages/USER-QUIP.cmake b/cmake/Modules/Packages/USER-QUIP.cmake index 93096a2f54..52ba7e9c47 100644 --- a/cmake/Modules/Packages/USER-QUIP.cmake +++ b/cmake/Modules/Packages/USER-QUIP.cmake @@ -1,5 +1,5 @@ if(PKG_USER-QUIP) enable_language(Fortran) find_package(QUIP REQUIRED) - list(APPEND LAMMPS_LINK_LIBS ${QUIP_LIBRARIES} ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${LAPACK_LIBRARIES}) endif() diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index 8bb9e63605..0fac1fe919 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -49,28 +49,28 @@ if(PKG_USER-SCAFACOS) set(SCAFACOS_INCLUDE_DIRS ${SCAFACOS_BUILD_DIR}/include) list(APPEND LAMMPS_DEPS scafacos_build) # list and order from pkg_config file of ScaFaCoS build - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_direct.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_ewald.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_fmm.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_p2nfft.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_p3m.a) - list(APPEND LAMMPS_LINK_LIBS ${GSL_LIBRARIES}) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_near.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_gridsort.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_resort.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_redist.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_common.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_pnfft.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_pfft.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3_mpi.a) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3.a) - list(APPEND LAMMPS_LINK_LIBS ${MPI_Fortran_LIBRARIES}) - list(APPEND LAMMPS_LINK_LIBS ${MPI_C_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_direct.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_ewald.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_fmm.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_p2nfft.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_p3m.a) + target_link_libraries(lammps PRIVATE ${GSL_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_near.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_gridsort.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_resort.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_redist.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_common.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_pnfft.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_pfft.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3_mpi.a) + target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_fftw3.a) + target_link_libraries(lammps PRIVATE ${MPI_Fortran_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${MPI_C_LIBRARIES}) else() find_package(PkgConfig REQUIRED) pkg_check_modules(SCAFACOS REQUIRED scafacos) - list(APPEND LAMMPS_LINK_LIBS ${SCAFACOS_LDFLAGS}) + target_link_libraries(lammps PRIVATE ${SCAFACOS_LDFLAGS}) endif() include_directories(${SCAFACOS_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-VTK.cmake b/cmake/Modules/Packages/USER-VTK.cmake index d264577ca2..fb69f115b2 100644 --- a/cmake/Modules/Packages/USER-VTK.cmake +++ b/cmake/Modules/Packages/USER-VTK.cmake @@ -2,5 +2,5 @@ if(PKG_USER-VTK) find_package(VTK REQUIRED NO_MODULE) include(${VTK_USE_FILE}) add_definitions(-DLAMMPS_VTK) - list(APPEND LAMMPS_LINK_LIBS ${VTK_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${VTK_LIBRARIES}) endif() diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index 5418132034..f567c35597 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -39,5 +39,5 @@ if(PKG_VORONOI) endif() endif() include_directories(${VORO_INCLUDE_DIRS}) - list(APPEND LAMMPS_LINK_LIBS ${VORO_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${VORO_LIBRARIES}) endif() -- GitLab From 0e3f4f3de2bd7ad50a70353e9e749758796cb10d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 19:07:23 -0600 Subject: [PATCH 064/577] cmake: remove LAMMPS_DEPS --- cmake/CMakeLists.txt | 12 +----------- cmake/Modules/MPI4WIN.cmake | 2 +- cmake/Modules/Packages/KIM.cmake | 2 +- cmake/Modules/Packages/LATTE.cmake | 2 +- cmake/Modules/Packages/MSCG.cmake | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 2 +- cmake/Modules/Packages/USER-SCAFACOS.cmake | 2 +- cmake/Modules/Packages/USER-SMD.cmake | 2 +- cmake/Modules/Packages/VORONOI.cmake | 2 +- 9 files changed, 9 insertions(+), 19 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 9190374a2e..b9e8d5b919 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -126,7 +126,6 @@ endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) include(GNUInstallDirs) -set(LAMMPS_DEPS) set(LAMMPS_API_DEFINES) set(DEFAULT_PACKAGES ASPHERE BODY CLASS2 COLLOID COMPRESS CORESHELL DIPOLE @@ -526,7 +525,7 @@ add_custom_target(gitversion COMMAND ${CMAKE_COMMAND} -DLAMMPS_STYLE_HEADERS_DIR="${LAMMPS_STYLE_HEADERS_DIR}" -P ${CMAKE_CURRENT_SOURCE_DIR}/Modules/generate_lmpgitversion.cmake) set_property(DIRECTORY APPEND PROPERTY ADDITIONAL_MAKE_CLEAN_FILES ${LAMMPS_STYLE_HEADERS_DIR}/gitversion.h) -list(APPEND LAMMPS_DEPS gitversion) +add_dependencies(lammps gitversion) ########################################### # Actually add executable and lib to build @@ -537,9 +536,6 @@ if (${_index} GREATER -1) target_link_libraries(lammps PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) endif() if(BUILD_LIB) - if(LAMMPS_DEPS) - add_dependencies(lammps ${LAMMPS_DEPS}) - endif() set(LAMMPS_CXX_HEADERS ${LAMMPS_SOURCE_DIR}/angle.h ${LAMMPS_SOURCE_DIR}/atom.h @@ -584,12 +580,6 @@ if(BUILD_LIB) endif() if(BUILD_EXE) - if(NOT BUILD_LIB) - if(LAMMPS_DEPS) - add_dependencies(${LAMMPS_EXE} ${LAMMPS_DEPS}) - endif() - endif() - set_target_properties(${LAMMPS_EXE} PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) install(TARGETS ${LAMMPS_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1) diff --git a/cmake/Modules/MPI4WIN.cmake b/cmake/Modules/MPI4WIN.cmake index 1f3195041a..1fe6daada3 100644 --- a/cmake/Modules/MPI4WIN.cmake +++ b/cmake/Modules/MPI4WIN.cmake @@ -19,5 +19,5 @@ ExternalProject_get_property(mpi4win_build SOURCE_DIR) add_definitions(-DMPICH_SKIP_MPICXX) include_directories("${SOURCE_DIR}/include") set(MPI4WIN_LIBRARIES "${SOURCE_DIR}/lib/libmpi.a") -list(APPEND LAMMPS_DEPS mpi4win_build) +add_dependencies(lammps mpi4win_build) set(LAMMPS_USE_MPI4WIN ON) diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 002fbbcaed..56fc1449fa 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -57,7 +57,7 @@ if(PKG_KIM) ExternalProject_get_property(kim_build INSTALL_DIR) set(KIM-API_INCLUDE_DIRS ${INSTALL_DIR}/include/kim-api) set(KIM-API_LDFLAGS ${INSTALL_DIR}/${_KIM_LIBDIR}/libkim-api${CMAKE_SHARED_LIBRARY_SUFFIX}) - list(APPEND LAMMPS_DEPS kim_build) + add_dependencies(lammps kim_build) else() find_package(KIM-API ${KIM-API_MIN_VERSION} REQUIRED) endif() diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index 55d9b31797..abadd1cd97 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -24,7 +24,7 @@ if(PKG_LATTE) -DCMAKE_MAKE_PROGRAM=${CMAKE_MAKE_PROGRAM} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} BUILD_BYPRODUCTS /${_LATTE_LIBDIR}/liblatte.a ) - list(APPEND LAMMPS_DEPS latte_build) + add_dependencies(lammps latte_build) ExternalProject_get_property(latte_build INSTALL_DIR) set(LATTE_LIBRARIES ${INSTALL_DIR}/${_LATTE_LIBDIR}/liblatte.a) else() diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index e300ed6ae2..2c63e69fa7 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -32,7 +32,7 @@ if(PKG_MSCG) set(MSCG_LIBRARIES ${BINARY_DIR}/libmscg.a) ExternalProject_get_property(mscg_build SOURCE_DIR) set(MSCG_INCLUDE_DIRS ${SOURCE_DIR}/src) - list(APPEND LAMMPS_DEPS mscg_build) + add_dependencies(lammps mscg_build) if(NOT LAPACK_FOUND) file(MAKE_DIRECTORY ${MSCG_INCLUDE_DIRS}) add_dependencies(mscg_build linalg) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index 9669f1955c..2bca281fa8 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -67,7 +67,7 @@ if(PKG_USER-PLUMED) ) ExternalProject_get_property(plumed_build INSTALL_DIR) set(PLUMED_INSTALL_DIR ${INSTALL_DIR}) - list(APPEND LAMMPS_DEPS plumed_build) + add_dependencies(lammps plumed_build) if(PLUMED_MODE STREQUAL "STATIC") add_definitions(-D__PLUMED_WRAPPER_CXX=1) target_link_libraries(lammps ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index 0fac1fe919..ebd750c04b 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -47,7 +47,7 @@ if(PKG_USER-SCAFACOS) ExternalProject_get_property(scafacos_build INSTALL_DIR) set(SCAFACOS_BUILD_DIR ${INSTALL_DIR}) set(SCAFACOS_INCLUDE_DIRS ${SCAFACOS_BUILD_DIR}/include) - list(APPEND LAMMPS_DEPS scafacos_build) + add_dependencies(lammps scafacos_build) # list and order from pkg_config file of ScaFaCoS build target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs_direct.a) diff --git a/cmake/Modules/Packages/USER-SMD.cmake b/cmake/Modules/Packages/USER-SMD.cmake index a868918e37..eed60ae8bd 100644 --- a/cmake/Modules/Packages/USER-SMD.cmake +++ b/cmake/Modules/Packages/USER-SMD.cmake @@ -16,7 +16,7 @@ if(PKG_USER-SMD) ) ExternalProject_get_property(Eigen3_build SOURCE_DIR) set(EIGEN3_INCLUDE_DIR ${SOURCE_DIR}) - list(APPEND LAMMPS_DEPS Eigen3_build) + add_dependencies(lammps Eigen3_build) else() find_package(Eigen3 NO_MODULE) mark_as_advanced(Eigen3_DIR) diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index f567c35597..d2bb185228 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -31,7 +31,7 @@ if(PKG_VORONOI) ExternalProject_get_property(voro_build SOURCE_DIR) set(VORO_LIBRARIES ${SOURCE_DIR}/src/libvoro++.a) set(VORO_INCLUDE_DIRS ${SOURCE_DIR}/src) - list(APPEND LAMMPS_DEPS voro_build) + add_dependencies(lammps voro_build) else() find_package(VORO) if(NOT VORO_FOUND) -- GitLab From 3076e267073f7501467933cb846a1b129373e2fb Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 19:20:00 -0600 Subject: [PATCH 065/577] cmake: create imported target for FFTW --- cmake/Modules/FindFFTW3.cmake | 28 +++++++++++++++++++++++---- cmake/Modules/FindFFTW3F.cmake | 30 ++++++++++++++++++++++++----- cmake/Modules/Packages/KSPACE.cmake | 5 ++--- 3 files changed, 51 insertions(+), 12 deletions(-) diff --git a/cmake/Modules/FindFFTW3.cmake b/cmake/Modules/FindFFTW3.cmake index 63752f85df..708ec49509 100644 --- a/cmake/Modules/FindFFTW3.cmake +++ b/cmake/Modules/FindFFTW3.cmake @@ -14,14 +14,34 @@ find_path(FFTW3_INCLUDE_DIR fftw3.h HINTS ${PC_FFTW3_INCLUDE_DIRS}) find_library(FFTW3_LIBRARY NAMES fftw3 HINTS ${PC_FFTW3_LIBRARY_DIRS}) find_library(FFTW3_OMP_LIBRARY NAMES fftw3_omp HINTS ${PC_FFTW3_LIBRARY_DIRS}) -set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR}) -set(FFTW3_LIBRARIES ${FFTW3_LIBRARY}) -set(FFTW3_OMP_LIBRARIES ${FFTW3_OMP_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set FFTW3_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(FFTW3 DEFAULT_MSG FFTW3_LIBRARY FFTW3_INCLUDE_DIR) +# Copy the results to the output variables and target. +if(FFTW3_FOUND) + set(FFTW3_LIBRARIES ${FFTW3_LIBRARY} ) + set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR} ) + + if(NOT TARGET FFTW3::FFTW3) + add_library(FFTW3::FFTW3 UNKNOWN IMPORTED) + set_target_properties(FFTW3::FFTW3 PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIRS}") + endif() + if(FFTW3_OMP_LIBRARY) + set(FFTW3_OMP_LIBRARIES ${FFTW3_OMP_LIBRARY}) + if(NOT TARGET FFTW3::FFTW3_OMP) + add_library(FFTW3::FFTW3_OMP UNKNOWN IMPORTED) + set_target_properties(FFTW3::FFTW3_OMP PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3_OMP_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3_INCLUDE_DIRS}") + endif() + endif() +endif() + mark_as_advanced(FFTW3_INCLUDE_DIR FFTW3_LIBRARY FFTW3_OMP_LIBRARY) diff --git a/cmake/Modules/FindFFTW3F.cmake b/cmake/Modules/FindFFTW3F.cmake index c67aa5faf1..3dbcdaa04e 100644 --- a/cmake/Modules/FindFFTW3F.cmake +++ b/cmake/Modules/FindFFTW3F.cmake @@ -13,14 +13,34 @@ find_path(FFTW3F_INCLUDE_DIR fftw3.h HINTS ${PC_FFTW3F_INCLUDE_DIRS}) find_library(FFTW3F_LIBRARY NAMES fftw3f HINTS ${PC_FFTW3F_LIBRARY_DIRS}) find_library(FFTW3F_OMP_LIBRARY NAMES fftw3f_omp HINTS ${PC_FFTW3F_LIBRARY_DIRS}) -set(FFTW3F_INCLUDE_DIRS ${FFTW3F_INCLUDE_DIR}) -set(FFTW3F_LIBRARIES ${FFTW3F_LIBRARY}) -set(FFTW3F_OMP_LIBRARIES ${FFTW3F_OMP_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set FFTW3F_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(FFTW3F DEFAULT_MSG FFTW3F_LIBRARY FFTW3F_INCLUDE_DIR) -mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY) +# Copy the results to the output variables and target. +if(FFTW3F_FOUND) + set(FFTW3F_LIBRARIES ${FFTW3F_LIBRARY} ) + set(FFTW3F_INCLUDE_DIRS ${FFTW3F_INCLUDE_DIR} ) + + if(NOT TARGET FFTW3F::FFTW3F) + add_library(FFTW3F::FFTW3F UNKNOWN IMPORTED) + set_target_properties(FFTW3F::FFTW3F PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3F_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3F_INCLUDE_DIRS}") + endif() + if(FFTW3F_OMP_LIBRARY) + set(FFTW3F_OMP_LIBRARIES ${FFTW3F_OMP_LIBRARY}) + if(NOT TARGET FFTW3F::FFTW3F_OMP) + add_library(FFTW3F::FFTW3F_OMP UNKNOWN IMPORTED) + set_target_properties(FFTW3F::FFTW3F_OMP PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES "C" + IMPORTED_LOCATION "${FFTW3F_OMP_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${FFTW3F_INCLUDE_DIRS}") + endif() + endif() +endif() + +mark_as_advanced(FFTW3F_INCLUDE_DIR FFTW3F_LIBRARY FFTW3F_OMP_LIBRARY) diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index 4f92a6963c..db12787013 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -19,8 +19,7 @@ if(PKG_KSPACE) if(FFT STREQUAL "FFTW3") find_package(${FFTW} REQUIRED) add_definitions(-DFFT_FFTW3) - include_directories(${${FFTW}_INCLUDE_DIRS}) - target_link_libraries(lammps PRIVATE ${${FFTW}_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) else() @@ -30,7 +29,7 @@ if(PKG_KSPACE) if(FFT_FFTW_THREADS) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) add_definitions(-DFFT_FFTW_THREADS) - target_link_libraries(lammps PRIVATE ${${FFTW}_OMP_LIBRARIES}) + target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}_OMP) else() message(FATAL_ERROR "Need OpenMP enabled FFTW3 library for FFT_THREADS") endif() -- GitLab From 591212af3ac3a6c0d5f9fce59199b39b279929e8 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 19:57:48 -0600 Subject: [PATCH 066/577] cmake: add back include path for now --- cmake/CMakeLists.txt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b9e8d5b919..c6d149e7d6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -112,15 +112,17 @@ if(BUILD_LIB) add_library(lammps ${ALL_SOURCES}) if(BUILD_EXE) add_executable(lmp ${MAIN_SOURCES}) - set(LAMMPS_EXE lmp) target_link_libraries(lmp PRIVATE lammps) + set_target_properties(lmp PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) + install(TARGETS lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() else() if(NOT BUILD_EXE) message(FATAL_ERROR "You need to at least enable one of two following options: BUILD_LIB or BUILD_EXE") endif() add_executable(lammps ${ALL_SOURCES}) - set(LAMMPS_EXE lammps) + set_target_properties(lammps PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) + install(TARGETS lammps DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) @@ -186,6 +188,7 @@ if(BUILD_MPI) include(MPI4WIN) else() find_package(MPI REQUIRED) + include_directories(${MPI_CXX_INCLUDE_PATH}) add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) target_link_libraries(lammps PRIVATE MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) @@ -580,8 +583,6 @@ if(BUILD_LIB) endif() if(BUILD_EXE) - set_target_properties(${LAMMPS_EXE} PROPERTIES OUTPUT_NAME ${LAMMPS_BINARY}) - install(TARGETS ${LAMMPS_EXE} DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/lammps.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1 RENAME ${LAMMPS_BINARY}.1) endif() -- GitLab From a42f7163d222367003c291e7c307521966c9a266 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Sun, 22 Mar 2020 21:29:15 -0600 Subject: [PATCH 067/577] cmake: move include up --- cmake/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index c6d149e7d6..ae80996196 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -105,6 +105,7 @@ endif() option(BUILD_TOOLS "Build and install LAMMPS tools (msi2lmp, binary2txt, chain)" OFF) +include(GNUInstallDirs) file(GLOB ALL_SOURCES ${LAMMPS_SOURCE_DIR}/[^.]*.cpp) if(BUILD_LIB) file(GLOB MAIN_SOURCES ${LAMMPS_SOURCE_DIR}/main.cpp) @@ -126,7 +127,6 @@ else() endif() option(CMAKE_VERBOSE_MAKEFILE "Generate verbose Makefiles" OFF) -include(GNUInstallDirs) set(LAMMPS_API_DEFINES) -- GitLab From 6ee25db32a46c80da89a69ccfa667e283404ff3a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 08:00:51 -0600 Subject: [PATCH 068/577] cmake: fftw needs to be public due to DSO --- cmake/Modules/Packages/KSPACE.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index db12787013..2a586dccf3 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -19,7 +19,7 @@ if(PKG_KSPACE) if(FFT STREQUAL "FFTW3") find_package(${FFTW} REQUIRED) add_definitions(-DFFT_FFTW3) - target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}) + target_link_libraries(lammps PUBLIC ${FFTW}::${FFTW}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) else() -- GitLab From 9b8266173faff9ab80e77461be42e566e658491e Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 08:23:16 -0600 Subject: [PATCH 069/577] cmake: JPEG imported target is >=cmake-3.12 only --- cmake/CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index ae80996196..6dd80d3253 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -284,7 +284,12 @@ option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND}) if(WITH_JPEG) find_package(JPEG REQUIRED) add_definitions(-DLAMMPS_JPEG) - target_link_libraries(lammps PRIVATE JPEG::JPEG) + if(CMAKE_VERSION VERSION_LESS 3.12) + include_directories(${JPEG_INCLUDE_DIR}) + target_link_libraries(lammps PRIVATE ${JPEG_LIBRARIES}) + else() + target_link_libraries(lammps PRIVATE JPEG::JPEG) + endif() endif() find_package(PNG QUIET) -- GitLab From d92b9ba8d0c38de37c1699dbcaecfce7931766db Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 08:51:29 -0600 Subject: [PATCH 070/577] cmake: mpi needs to be public due to DSO --- cmake/CMakeLists.txt | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 6dd80d3253..362cce94db 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -190,7 +190,7 @@ if(BUILD_MPI) find_package(MPI REQUIRED) include_directories(${MPI_CXX_INCLUDE_PATH}) add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) - target_link_libraries(lammps PRIVATE MPI::MPI_CXX) + target_link_libraries(lammps PUBLIC MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) if(LAMMPS_LONGLONG_TO_LONG) add_definitions(-DLAMMPS_LONGLONG_TO_LONG) diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index 2bca281fa8..a6cd20adbb 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -70,7 +70,7 @@ if(PKG_USER-PLUMED) add_dependencies(lammps plumed_build) if(PLUMED_MODE STREQUAL "STATIC") add_definitions(-D__PLUMED_WRAPPER_CXX=1) - target_link_libraries(lammps ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) + target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "SHARED") target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "RUNTIME") -- GitLab From 0f00bb1ca6c08c3d5fcc14857f2a629fd9c8292d Mon Sep 17 00:00:00 2001 From: david-castillo Date: Mon, 23 Mar 2020 16:48:08 +0100 Subject: [PATCH 071/577] Added new argument r0stop to fix restrain bond Added new fix restrain lowerbound harmonic --- doc/src/fix_restrain.rst | 33 +++++++++- src/fix_restrain.cpp | 133 ++++++++++++++++++++++++++++++++++++--- src/fix_restrain.h | 4 +- 3 files changed, 160 insertions(+), 10 deletions(-) diff --git a/doc/src/fix_restrain.rst b/doc/src/fix_restrain.rst index 3965cee04d..9b9beaa5ac 100644 --- a/doc/src/fix_restrain.rst +++ b/doc/src/fix_restrain.rst @@ -17,10 +17,18 @@ Syntax .. parsed-literal:: - *bond* args = atom1 atom2 Kstart Kstop r0 + *bond* args = atom1 atom2 Kstart Kstop r0start r0stop atom1,atom2 = IDs of 2 atoms in bond Kstart,Kstop = restraint coefficients at start/end of run (energy units) - r0 = equilibrium bond distance (distance units) + r0start = equilibrium bond distance at start of run (distance units) + r0stop = equilibrium bond distance at end of run (distance units). If not + specified it's assumed to be equal to r0start + *lbond* args = atom1 atom2 Kstart Kstop r0start r0stop + atom1,atom2 = IDs of 2 atoms in bond + Kstart,Kstop = restraint coefficients at start/end of run (energy units) + r0start = equilibrium bond distance at start of run (distance units) + r0stop = equilibrium bond distance at end of run (distance units). If not + specified it's assumed to be equal to r0start *angle* args = atom1 atom2 atom3 Kstart Kstop theta0 atom1,atom2,atom3 = IDs of 3 atoms in angle, atom2 = middle atom Kstart,Kstop = restraint coefficients at start/end of run (energy units) @@ -38,6 +46,7 @@ Examples .. code-block:: LAMMPS fix holdem all restrain bond 45 48 2000.0 2000.0 2.75 + fix holdem all restrain lbond 45 48 2000.0 2000.0 2.75 fix holdem all restrain dihedral 1 2 3 4 2000.0 2000.0 120.0 fix holdem all restrain bond 45 48 2000.0 2000.0 2.75 dihedral 1 2 3 4 2000.0 2000.0 120.0 fix texas_holdem all restrain dihedral 1 2 3 4 0.0 2000.0 120.0 dihedral 1 2 3 5 0.0 2000.0 -120.0 dihedral 1 2 3 6 0.0 2000.0 0.0 @@ -141,6 +150,26 @@ is included in :math:`K`. ---------- +The *lbond* keyword applies a lowerbound bond restraint to the specified atoms +using the same functional form used by the :doc:`bond_style harmonic ` command if the distance between +the atoms is smaller than the equilibrium bond distance and 0 otherwise. The potential associated with +the restraint is + +.. math:: + + E = K (r - r_0)^2 if r < r_0 + E = 0 if r >= r_0 + +with the following coefficients: + +* :math:`K` (energy/distance\^2) +* :math:`r_0` (distance) + +:math:`K` and :math:`r_0` are specified with the fix. Note that the usual 1/2 factor +is included in :math:`K`. + +---------- + The *angle* keyword applies an angle restraint to the specified atoms using the same functional form used by the :doc:`angle_style harmonic ` command. The potential associated with the restraint is diff --git a/src/fix_restrain.cpp b/src/fix_restrain.cpp index 5a0d4fb662..5f65d7069b 100644 --- a/src/fix_restrain.cpp +++ b/src/fix_restrain.cpp @@ -34,7 +34,7 @@ using namespace LAMMPS_NS; using namespace FixConst; using namespace MathConst; -enum{BOND,ANGLE,DIHEDRAL}; +enum{BOND,LBOUND,ANGLE,DIHEDRAL}; #define TOLERANCE 0.05 #define SMALL 0.001 @@ -45,7 +45,7 @@ enum{BOND,ANGLE,DIHEDRAL}; FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : Fix(lmp, narg, arg), rstyle(NULL), mult(NULL), ids(NULL), kstart(NULL), kstop(NULL), target(NULL), - cos_target(NULL), sin_target(NULL) + deqstart(NULL), deqstop(NULL), cos_target(NULL), sin_target(NULL) { if (narg < 4) error->all(FLERR,"Illegal fix restrain command"); @@ -72,6 +72,8 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : memory->grow(kstart,maxrestrain,"restrain:kstart"); memory->grow(kstop,maxrestrain,"restrain:kstop"); memory->grow(target,maxrestrain,"restrain:target"); + memory->grow(deqstart,maxrestrain,"restrain:deqstart"); + memory->grow(deqstop,maxrestrain,"restrain:deqstop"); memory->grow(cos_target,maxrestrain,"restrain:cos_target"); memory->grow(sin_target,maxrestrain,"restrain:sin_target"); } @@ -83,8 +85,29 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]); kstart[nrestrain] = force->numeric(FLERR,arg[iarg+3]); kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); - target[nrestrain] = force->numeric(FLERR,arg[iarg+5]); - iarg += 6; + deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + if (iarg+6 == narg) { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; + } else { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; + } + } else if (strcmp(arg[iarg],"lbound") == 0) { + if (iarg+6 > narg) error->all(FLERR,"Illegal fix restrain command"); + rstyle[nrestrain] = LBOUND; + ids[nrestrain][0] = force->inumeric(FLERR,arg[iarg+1]); + ids[nrestrain][1] = force->inumeric(FLERR,arg[iarg+2]); + kstart[nrestrain] = force->numeric(FLERR,arg[iarg+3]); + kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); + deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + if (iarg+6 == narg) { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; + } else { + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; + } } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+7 > narg) error->all(FLERR,"Illegal fix restrain command"); rstyle[nrestrain] = ANGLE; @@ -139,6 +162,8 @@ FixRestrain::~FixRestrain() memory->destroy(kstart); memory->destroy(kstop); memory->destroy(target); + memory->destroy(deqstart); + memory->destroy(deqstop); memory->destroy(cos_target); memory->destroy(sin_target); } @@ -192,11 +217,13 @@ void FixRestrain::post_force(int /*vflag*/) energy = 0.0; ebond = 0.0; + elbound = 0.0; eangle = 0.0; edihed = 0.0; for (int m = 0; m < nrestrain; m++) if (rstyle[m] == BOND) restrain_bond(m); + else if (rstyle[m] == LBOUND) restrain_lbound(m); else if (rstyle[m] == ANGLE) restrain_angle(m); else if (rstyle[m] == DIHEDRAL) restrain_dihedral(m); } @@ -233,6 +260,7 @@ void FixRestrain::restrain_bond(int m) double delta = update->ntimestep - update->beginstep; if (delta != 0.0) delta /= update->endstep - update->beginstep; double k = kstart[m] + delta * (kstop[m] - kstart[m]); + double deq = deqstart[m] + delta * (deqstop[m] - deqstart[m]); i1 = atom->map(ids[m][0]); i2 = atom->map(ids[m][1]); @@ -269,7 +297,7 @@ void FixRestrain::restrain_bond(int m) rsq = delx*delx + dely*dely + delz*delz; r = sqrt(rsq); - dr = r - target[m]; + dr = r - deq; rk = k * dr; // force & energy @@ -277,7 +305,7 @@ void FixRestrain::restrain_bond(int m) if (r > 0.0) fbond = -2.0*rk/r; else fbond = 0.0; - ebond += rk*dr; + ebond += rk*dr; energy += rk*dr; // apply force to each of 2 atoms @@ -295,6 +323,94 @@ void FixRestrain::restrain_bond(int m) } } +/* ---------------------------------------------------------------------- + apply harmonic lower-bound bond restraints +---------------------------------------------------------------------- */ + +void FixRestrain::restrain_lbound(int m) +{ + int i1,i2; + double delx,dely,delz,fbond; + double rsq,r,dr,rk; + + double **x = atom->x; + double **f = atom->f; + int nlocal = atom->nlocal; + int newton_bond = force->newton_bond; + + double delta = update->ntimestep - update->beginstep; + if (delta != 0.0) delta /= update->endstep - update->beginstep; + double k = kstart[m] + delta * (kstop[m] - kstart[m]); + double deq = deqstart[m] + delta * (deqstop[m] - deqstart[m]); + + i1 = atom->map(ids[m][0]); + i2 = atom->map(ids[m][1]); + + // newton_bond on: only processor owning i2 computes restraint + // newton_bond off: only processors owning either of i1,i2 computes restraint + + if (newton_bond) { + if (i2 == -1 || i2 >= nlocal) return; + if (i1 == -1) { + char str[128]; + sprintf(str, + "Restrain atoms %d %d missing on proc %d at step " BIGINT_FORMAT, + ids[m][0],ids[m][1], + comm->me,update->ntimestep); + error->one(FLERR,str); + } + } else { + if ((i1 == -1 || i1 >= nlocal) && (i2 == -1 || i2 >= nlocal)) return; + if (i1 == -1 || i2 == -1) { + char str[128]; + sprintf(str, + "Restrain atoms %d %d missing on proc %d at step " BIGINT_FORMAT, + ids[m][0],ids[m][1], + comm->me,update->ntimestep); + error->one(FLERR,str); + } + } + + delx = x[i1][0] - x[i2][0]; + dely = x[i1][1] - x[i2][1]; + delz = x[i1][2] - x[i2][2]; + domain->minimum_image(delx,dely,delz); + + rsq = delx*delx + dely*dely + delz*delz; + r = sqrt(rsq); + dr = r - deq; + rk = k * dr; + + // force & energy + + if (dr < 0) { + if (r > 0.0) fbond = -2.0*rk/r; + else fbond = 0.0; + + elbound += rk*dr; + energy += rk*dr; + } else { + fbond = 0.0; + + elbound += 0.0; + energy += 0.0; + } + + // apply force to each of 2 atoms + + 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; + } +} + /* ---------------------------------------------------------------------- apply harmonic angle restraints ---------------------------------------------------------------------- */ @@ -655,9 +771,12 @@ double FixRestrain::compute_vector(int n) MPI_Allreduce(&ebond,&ebond_all,1,MPI_DOUBLE,MPI_SUM,world); return ebond_all; } else if (n == 1) { + MPI_Allreduce(&elbound,&elbound_all,1,MPI_DOUBLE,MPI_SUM,world); + return elbound_all; + } else if (n == 3) { MPI_Allreduce(&eangle,&eangle_all,1,MPI_DOUBLE,MPI_SUM,world); return eangle_all; - } else if (n == 2) { + } else if (n == 4) { MPI_Allreduce(&edihed,&edihed_all,1,MPI_DOUBLE,MPI_SUM,world); return edihed_all; } else { diff --git a/src/fix_restrain.h b/src/fix_restrain.h index 4572905d46..3497b7daf5 100644 --- a/src/fix_restrain.h +++ b/src/fix_restrain.h @@ -44,14 +44,16 @@ class FixRestrain : public Fix { int *rstyle; int *mult; int **ids; - double *kstart,*kstop,*target; + double *kstart,*kstop,*deqstart,*deqstop,*target; double *cos_target,*sin_target; double energy,energy_all; double ebond,ebond_all; + double elbound,elbound_all; double eangle,eangle_all; double edihed,edihed_all; void restrain_bond(int); + void restrain_lbound(int); void restrain_angle(int); void restrain_dihedral(int); }; -- GitLab From 6209479797e29df62dd17476127e30a64d73d08f Mon Sep 17 00:00:00 2001 From: david-castillo Date: Mon, 23 Mar 2020 17:57:58 +0100 Subject: [PATCH 072/577] Removed some tabs Changed mathjax for multiline formula --- doc/src/fix_restrain.rst | 9 ++++++--- src/fix_restrain.cpp | 16 ++++++++-------- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/doc/src/fix_restrain.rst b/doc/src/fix_restrain.rst index 9b9beaa5ac..110b26680d 100644 --- a/doc/src/fix_restrain.rst +++ b/doc/src/fix_restrain.rst @@ -150,16 +150,19 @@ is included in :math:`K`. ---------- -The *lbond* keyword applies a lowerbound bond restraint to the specified atoms +The *lbond* keyword applies a lower bound bond restraint to the specified atoms using the same functional form used by the :doc:`bond_style harmonic ` command if the distance between the atoms is smaller than the equilibrium bond distance and 0 otherwise. The potential associated with the restraint is .. math:: - E = K (r - r_0)^2 if r < r_0 - E = 0 if r >= r_0 + E = K (r - r_0)^2 ,if\;r < r_0 +.. math:: + + E = 0 \qquad\quad\quad ,if\;r \ge r_0 + with the following coefficients: * :math:`K` (energy/distance\^2) diff --git a/src/fix_restrain.cpp b/src/fix_restrain.cpp index 5f65d7069b..a6793a36be 100644 --- a/src/fix_restrain.cpp +++ b/src/fix_restrain.cpp @@ -87,11 +87,11 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); if (iarg+6 == narg) { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); - iarg += 6; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; } else { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); - iarg += 7; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; } } else if (strcmp(arg[iarg],"lbound") == 0) { if (iarg+6 > narg) error->all(FLERR,"Illegal fix restrain command"); @@ -102,11 +102,11 @@ FixRestrain::FixRestrain(LAMMPS *lmp, int narg, char **arg) : kstop[nrestrain] = force->numeric(FLERR,arg[iarg+4]); deqstart[nrestrain] = force->numeric(FLERR,arg[iarg+5]); if (iarg+6 == narg) { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); - iarg += 6; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+5]); + iarg += 6; } else { - deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); - iarg += 7; + deqstop[nrestrain] = force->numeric(FLERR,arg[iarg+6]); + iarg += 7; } } else if (strcmp(arg[iarg],"angle") == 0) { if (iarg+7 > narg) error->all(FLERR,"Illegal fix restrain command"); -- GitLab From e76afb33edc939ee63d2033e750d186bc2799c5a Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Mon, 23 Mar 2020 12:06:58 -0600 Subject: [PATCH 073/577] cmake: update to new target_link_libraries() signature --- cmake/CMakeLists.txt | 8 ++++---- cmake/Modules/Packages/GPU.cmake | 4 ++-- cmake/Modules/Packages/USER-H5MD.cmake | 2 +- cmake/pkgconfig/liblammps.pc.in | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 362cce94db..cc9b3fc56a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -457,14 +457,14 @@ foreach(SIMPLE_LIB POEMS USER-ATC USER-AWPMD USER-H5MD) endforeach() if(PKG_USER-AWPMD) - target_link_libraries(awpmd ${LAPACK_LIBRARIES}) + target_link_libraries(awpmd PRIVATE ${LAPACK_LIBRARIES}) endif() if(PKG_USER-ATC) if(LAMMPS_SIZES STREQUAL BIGBIG) message(FATAL_ERROR "The USER-ATC Package is not compatible with -DLAMMPS_BIGBIG") endif() - target_link_libraries(atc ${LAPACK_LIBRARIES}) + target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES}) endif() include(Packages/USER-H5MD) @@ -599,7 +599,7 @@ if(BUILD_TOOLS) if(CMAKE_GENERATOR_SUPPORT_FORTRAN) enable_language(Fortran) add_executable(chain.x ${LAMMPS_TOOLS_DIR}/chain.f) - target_link_libraries(chain.x ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) + target_link_libraries(chain.x PRIVATE ${CMAKE_Fortran_IMPLICIT_LINK_LIBRARIES}) install(TARGETS chain.x DESTINATION ${CMAKE_INSTALL_BINDIR}) else() message(WARNING "CMake build doesn't support fortran, skipping building 'chain.x'") @@ -609,7 +609,7 @@ if(BUILD_TOOLS) get_filename_component(MSI2LMP_SOURCE_DIR ${LAMMPS_TOOLS_DIR}/msi2lmp/src ABSOLUTE) file(GLOB MSI2LMP_SOURCES ${MSI2LMP_SOURCE_DIR}/[^.]*.c) add_executable(msi2lmp ${MSI2LMP_SOURCES}) - target_link_libraries(msi2lmp m) + target_link_libraries(msi2lmp PRIVATE ${MATH_LIBRARIES}) install(TARGETS msi2lmp DESTINATION ${CMAKE_INSTALL_BINDIR}) install(FILES ${LAMMPS_DOC_DIR}/msi2lmp.1 DESTINATION ${CMAKE_INSTALL_MANDIR}/man1) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index 427644f9c7..95bb525dd5 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -99,7 +99,7 @@ if(PKG_GPU) add_library(gpu STATIC ${GPU_LIB_SOURCES} ${GPU_LIB_CUDPP_SOURCES} ${GPU_OBJS}) - target_link_libraries(gpu ${CUDA_LIBRARIES} ${CUDA_CUDA_LIBRARY}) + target_link_libraries(gpu PRIVATE ${CUDA_LIBRARIES} ${CUDA_CUDA_LIBRARY}) target_include_directories(gpu PRIVATE ${LAMMPS_LIB_BINARY_DIR}/gpu ${CUDA_INCLUDE_DIRS}) target_compile_definitions(gpu PRIVATE -D_${GPU_PREC_SETTING} -DMPI_GERYON -DUCL_NO_EXIT ${GPU_CUDA_MPS_FLAGS}) if(CUDPP_OPT) @@ -166,7 +166,7 @@ if(PKG_GPU) ) add_library(gpu STATIC ${GPU_LIB_SOURCES}) - target_link_libraries(gpu ${OpenCL_LIBRARIES}) + target_link_libraries(gpu PRIVATE ${OpenCL_LIBRARIES}) target_include_directories(gpu PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/gpu ${OpenCL_INCLUDE_DIRS}) target_compile_definitions(gpu PRIVATE -D_${GPU_PREC_SETTING} -D${OCL_TUNE}_OCL -DMPI_GERYON -DUCL_NO_EXIT) target_compile_definitions(gpu PRIVATE -DUSE_OPENCL) diff --git a/cmake/Modules/Packages/USER-H5MD.cmake b/cmake/Modules/Packages/USER-H5MD.cmake index 40ea7b7444..1e3fcf82ce 100644 --- a/cmake/Modules/Packages/USER-H5MD.cmake +++ b/cmake/Modules/Packages/USER-H5MD.cmake @@ -2,7 +2,7 @@ if(PKG_USER-H5MD) enable_language(C) find_package(HDF5 REQUIRED) - target_link_libraries(h5md ${HDF5_LIBRARIES}) + target_link_libraries(h5md PRIVATE ${HDF5_LIBRARIES}) target_include_directories(h5md PRIVATE ${HDF5_INCLUDE_DIRS}) include_directories(${HDF5_INCLUDE_DIRS}) endif() diff --git a/cmake/pkgconfig/liblammps.pc.in b/cmake/pkgconfig/liblammps.pc.in index a8710ca224..a89f992c4a 100644 --- a/cmake/pkgconfig/liblammps.pc.in +++ b/cmake/pkgconfig/liblammps.pc.in @@ -22,7 +22,7 @@ # CMakeLists.txt: # find_package(PkgConfig) # pkg_check_modules(LAMMPS IMPORTED_TARGET lammps) -# target_link_libraries( PkgConfig::LAMMPS) +# target_link_libraries( PRIVATE PkgConfig::LAMMPS) prefix=@CMAKE_INSTALL_PREFIX@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ -- GitLab From 572502b33d86a7b834dbbe5d646dee42c65e00e9 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 09:35:57 -0600 Subject: [PATCH 074/577] cmake: add_definitions() -> target_compile_definitions() --- cmake/CMakeLists.txt | 20 ++++++++++---------- cmake/Modules/MPI4WIN.cmake | 2 +- cmake/Modules/Packages/KIM.cmake | 6 +++--- cmake/Modules/Packages/KOKKOS.cmake | 4 ++-- cmake/Modules/Packages/KSPACE.cmake | 14 +++++++------- cmake/Modules/Packages/PYTHON.cmake | 2 +- cmake/Modules/Packages/USER-INTEL.cmake | 12 ++++++------ cmake/Modules/Packages/USER-NETCDF.cmake | 6 +++--- cmake/Modules/Packages/USER-OMP.cmake | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 8 ++++---- cmake/Modules/Packages/USER-VTK.cmake | 2 +- 11 files changed, 39 insertions(+), 39 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index cc9b3fc56a..b1d90af045 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -189,11 +189,11 @@ if(BUILD_MPI) else() find_package(MPI REQUIRED) include_directories(${MPI_CXX_INCLUDE_PATH}) - add_definitions(-DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) + target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) target_link_libraries(lammps PUBLIC MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) if(LAMMPS_LONGLONG_TO_LONG) - add_definitions(-DLAMMPS_LONGLONG_TO_LONG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_LONGLONG_TO_LONG) endif() endif() else() @@ -209,7 +209,7 @@ set(LAMMPS_SIZES_VALUES smallbig bigbig smallsmall) set_property(CACHE LAMMPS_SIZES PROPERTY STRINGS ${LAMMPS_SIZES_VALUES}) validate_option(LAMMPS_SIZES LAMMPS_SIZES_VALUES) string(TOUPPER ${LAMMPS_SIZES} LAMMPS_SIZES) -add_definitions(-DLAMMPS_${LAMMPS_SIZES}) +target_compile_definitions(lammps PRIVATE -DLAMMPS_${LAMMPS_SIZES}) set(LAMMPS_API_DEFINES "${LAMMPS_API_DEFINES} -DLAMMPS_${LAMMPS_SIZES}") # posix_memalign is not available on Windows @@ -219,12 +219,12 @@ else() set(LAMMPS_MEMALIGN "64" CACHE STRING "enables the use of the posix_memalign() call instead of malloc() when large chunks or memory are allocated by LAMMPS. Set to 0 to disable") endif() if(NOT ${LAMMPS_MEMALIGN} STREQUAL "0") - add_definitions(-DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) + target_compile_definitions(lammps PRIVATE -DLAMMPS_MEMALIGN=${LAMMPS_MEMALIGN}) endif() option(LAMMPS_EXCEPTIONS "enable the use of C++ exceptions for error messages (useful for library interface)" OFF) if(LAMMPS_EXCEPTIONS) - add_definitions(-DLAMMPS_EXCEPTIONS) + target_compile_definitions(lammps PUBLIC -DLAMMPS_EXCEPTIONS) set(LAMMPS_API_DEFINES "${LAMMPS_API_DEFINES} -DLAMMPS_EXCEPTIONS") endif() @@ -283,7 +283,7 @@ find_package(JPEG QUIET) option(WITH_JPEG "Enable JPEG support" ${JPEG_FOUND}) if(WITH_JPEG) find_package(JPEG REQUIRED) - add_definitions(-DLAMMPS_JPEG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_JPEG) if(CMAKE_VERSION VERSION_LESS 3.12) include_directories(${JPEG_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${JPEG_LIBRARIES}) @@ -303,7 +303,7 @@ if(WITH_PNG) find_package(PNG REQUIRED) find_package(ZLIB REQUIRED) target_link_libraries(lammps PRIVATE PNG::PNG ZLIB::ZLIB) - add_definitions(-DLAMMPS_PNG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_PNG) endif() find_program(GZIP_EXECUTABLE gzip) @@ -313,7 +313,7 @@ if(WITH_GZIP) if(NOT GZIP_FOUND) message(FATAL_ERROR "gzip executable not found") endif() - add_definitions(-DLAMMPS_GZIP) + target_compile_definitions(lammps PRIVATE -DLAMMPS_GZIP) endif() find_program(FFMPEG_EXECUTABLE ffmpeg) @@ -323,7 +323,7 @@ if(WITH_FFMPEG) if(NOT FFMPEG_FOUND) message(FATAL_ERROR "ffmpeg executable not found") endif() - add_definitions(-DLAMMPS_FFMPEG) + target_compile_definitions(lammps PRIVATE -DLAMMPS_FFMPEG) endif() if(BUILD_SHARED_LIBS) @@ -413,7 +413,7 @@ endforeach() # packages that need defines set foreach(PKG MPIIO) if(PKG_${PKG}) - add_definitions(-DLMP_${PKG}) + target_compile_definitions(lammps PRIVATE -DLMP_${PKG}) endif() endforeach() diff --git a/cmake/Modules/MPI4WIN.cmake b/cmake/Modules/MPI4WIN.cmake index 1fe6daada3..a02adca77d 100644 --- a/cmake/Modules/MPI4WIN.cmake +++ b/cmake/Modules/MPI4WIN.cmake @@ -16,7 +16,7 @@ else() endif() ExternalProject_get_property(mpi4win_build SOURCE_DIR) -add_definitions(-DMPICH_SKIP_MPICXX) +target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX) include_directories("${SOURCE_DIR}/include") set(MPI4WIN_LIBRARIES "${SOURCE_DIR}/lib/libmpi.a") add_dependencies(lammps mpi4win_build) diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 56fc1449fa..7d349f496b 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -3,16 +3,16 @@ if(PKG_KIM) find_package(CURL) if(CURL_FOUND) target_link_libraries(lammps PRIVATE CURL::libcurl) - add_definitions(-DLMP_KIM_CURL) + target_compile_definitions(lammps PRIVATE -DLMP_KIM_CURL) set(LMP_DEBUG_CURL OFF CACHE STRING "Set libcurl verbose mode on/off. If on, it displays a lot of verbose information about its operations.") mark_as_advanced(LMP_DEBUG_CURL) if(LMP_DEBUG_CURL) - add_definitions(-DLMP_DEBUG_CURL) + target_compile_definitions(lammps PRIVATE -DLMP_DEBUG_CURL) endif() set(LMP_NO_SSL_CHECK OFF CACHE STRING "Tell libcurl to not verify the peer. If on, the connection succeeds regardless of the names in the certificate. Insecure - Use with caution!") mark_as_advanced(LMP_NO_SSL_CHECK) if(LMP_NO_SSL_CHECK) - add_definitions(-DLMP_NO_SSL_CHECK) + target_compile_definitions(lammps PRIVATE -DLMP_NO_SSL_CHECK) endif() endif() find_package(KIM-API QUIET) diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 58d2c139f6..34c924790e 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -18,7 +18,7 @@ if(PKG_KOKKOS) include_directories(${Kokkos_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE kokkos) endif() - add_definitions(-DLMP_KOKKOS) + target_compile_definitions(lammps PRIVATE -DLMP_KOKKOS) set(KOKKOS_PKG_SOURCES_DIR ${LAMMPS_SOURCE_DIR}/KOKKOS) set(KOKKOS_PKG_SOURCES ${KOKKOS_PKG_SOURCES_DIR}/kokkos.cpp @@ -44,7 +44,7 @@ if(PKG_KOKKOS) ${KOKKOS_PKG_SOURCES_DIR}/remap_kokkos.cpp) if(KOKKOS_ENABLE_CUDA) if(NOT ${FFT} STREQUAL "KISS") - add_definitions(-DFFT_CUFFT) + target_compile_definitions(lammps PRIVATE -DFFT_CUFFT) target_link_libraries(lammps PRIVATE cufft) endif() endif() diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index 2a586dccf3..e2a42f3981 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -3,7 +3,7 @@ if(PKG_KSPACE) set(FFTW "FFTW3") if(FFT_SINGLE) set(FFTW "FFTW3F") - add_definitions(-DFFT_SINGLE) + target_compile_definitions(lammps PUBLIC -DFFT_SINGLE) endif() find_package(${FFTW} QUIET) if(${FFTW}_FOUND) @@ -18,7 +18,7 @@ if(PKG_KSPACE) if(FFT STREQUAL "FFTW3") find_package(${FFTW} REQUIRED) - add_definitions(-DFFT_FFTW3) + target_compile_definitions(lammps PUBLIC -DFFT_FFTW3) target_link_libraries(lammps PUBLIC ${FFTW}::${FFTW}) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) option(FFT_FFTW_THREADS "Use threaded FFTW library" ON) @@ -28,7 +28,7 @@ if(PKG_KSPACE) if(FFT_FFTW_THREADS) if(FFTW3_OMP_LIBRARY OR FFTW3F_OMP_LIBRARY) - add_definitions(-DFFT_FFTW_THREADS) + target_compile_definitions(lammps PRIVATE -DFFT_FFTW_THREADS) target_link_libraries(lammps PRIVATE ${FFTW}::${FFTW}_OMP) else() message(FATAL_ERROR "Need OpenMP enabled FFTW3 library for FFT_THREADS") @@ -36,16 +36,16 @@ if(PKG_KSPACE) endif() elseif(FFT STREQUAL "MKL") find_package(MKL REQUIRED) - add_definitions(-DFFT_MKL) + target_compile_definitions(lammps PRIVATE -DFFT_MKL) option(FFT_MKL_THREADS "Use threaded MKL FFT" ON) if(FFT_MKL_THREADS) - add_definitions(-DFFT_MKL_THREADS) + target_compile_definitions(lammps PRIVATE -DFFT_MKL_THREADS) endif() include_directories(${MKL_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() # last option is KISSFFT - add_definitions(-DFFT_KISS) + target_compile_definitions(lammps PRIVATE -DFFT_KISS) endif() set(FFT_PACK "array" CACHE STRING "Optimization for FFT") @@ -54,6 +54,6 @@ if(PKG_KSPACE) validate_option(FFT_PACK FFT_PACK_VALUES) if(NOT FFT_PACK STREQUAL "array") string(TOUPPER ${FFT_PACK} FFT_PACK) - add_definitions(-DFFT_PACK_${FFT_PACK}) + target_compile_definitions(lammps PRIVATE -DFFT_PACK_${FFT_PACK}) endif() endif() diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index 7d6e2999f7..4611fddb98 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -1,6 +1,6 @@ if(PKG_PYTHON) find_package(PythonLibs REQUIRED) - add_definitions(-DLMP_PYTHON) + target_compile_definitions(lammps PRIVATE -DLMP_PYTHON) include_directories(${PYTHON_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARY}) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 0a9b634bc7..96a897297f 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -4,7 +4,7 @@ if(PKG_USER-INTEL) message(FATAL_ERROR "immintrin.h header not found, Intel package won't work without it") endif() - add_definitions(-DLMP_USER_INTEL) + target_compile_definitions(lammps PRIVATE -DLMP_USER_INTEL) set(INTEL_ARCH "cpu" CACHE STRING "Architectures used by USER-INTEL (cpu or knl)") set(INTEL_ARCH_VALUES cpu knl) @@ -24,14 +24,14 @@ if(PKG_USER-INTEL) string(TOUPPER ${INTEL_LRT_MODE} INTEL_LRT_MODE) if(INTEL_LRT_MODE STREQUAL "THREADS") if(Threads_FOUND) - add_definitions(-DLMP_INTEL_USELRT) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_USELRT) target_link_libraries(lammps PRIVATE Threads::Threads) else() message(FATAL_ERROR "Must have working threads library for Long-range thread support") endif() endif() if(INTEL_LRT_MODE STREQUAL "C++11") - add_definitions(-DLMP_INTEL_USERLRT -DLMP_INTEL_LRT11) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_USERLRT -DLMP_INTEL_LRT11) endif() if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") @@ -46,7 +46,7 @@ if(PKG_USER-INTEL) if(TBB_FOUND) target_link_libraries(lammps PRIVATE ${TBB_MALLOC_LIBRARIES}) else() - add_definitions(-DLMP_INTEL_NO_TBB) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_NO_TBB) if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") message(WARNING "USER-INTEL with Intel compilers should use TBB malloc libraries") endif() @@ -54,7 +54,7 @@ if(PKG_USER-INTEL) find_package(MKL QUIET) if(MKL_FOUND) - add_definitions(-DLMP_USE_MKL_RNG) + target_compile_definitions(lammps PRIVATE -DLMP_USE_MKL_RNG) target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() message(STATUS "Pair style dpd/intel will be faster with MKL libraries") @@ -71,7 +71,7 @@ if(PKG_USER-INTEL) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -xHost -qopenmp -qoffload") set(MIC_OPTIONS "-qoffload-option,mic,compiler,\"-fp-model fast=2 -mGLOB_default_function_attrs=\\\"gather_scatter_loop_unroll=4\\\"\"") add_compile_options(-xMIC-AVX512 -qoffload -fno-alias -ansi-alias -restrict -qoverride-limits ${MIC_OPTIONS}) - add_definitions(-DLMP_INTEL_OFFLOAD) + target_compile_definitions(lammps PRIVATE -DLMP_INTEL_OFFLOAD) else() if(CMAKE_CXX_COMPILER_ID STREQUAL "Intel") include(CheckCXXCompilerFlag) diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index 8d62f5f7ec..2c12d2b799 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -11,14 +11,14 @@ if(PKG_USER-NETCDF) if(NETCDF_FOUND) include_directories(${NETCDF_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE ${NETCDF_LIBRARIES}) - add_definitions(-DLMP_HAS_NETCDF) + target_compile_definitions(lammps PRIVATE -DLMP_HAS_NETCDF) endif(NETCDF_FOUND) if(PNETCDF_FOUND) include_directories(${PNETCDF_INCLUDES}) target_link_libraries(lammps PRIVATE ${PNETCDF_LIBRARIES}) - add_definitions(-DLMP_HAS_PNETCDF) + target_compile_definitions(lammps PRIVATE -DLMP_HAS_PNETCDF) endif(PNETCDF_FOUND) - add_definitions(-DNC_64BIT_DATA=0x0020) + target_compile_definitions(lammps PRIVATE -DNC_64BIT_DATA=0x0020) endif() diff --git a/cmake/Modules/Packages/USER-OMP.cmake b/cmake/Modules/Packages/USER-OMP.cmake index 4b1a4b1571..91f0467a17 100644 --- a/cmake/Modules/Packages/USER-OMP.cmake +++ b/cmake/Modules/Packages/USER-OMP.cmake @@ -6,7 +6,7 @@ if(PKG_USER-OMP) ${USER-OMP_SOURCES_DIR}/fix_nh_omp.cpp ${USER-OMP_SOURCES_DIR}/fix_nh_sphere_omp.cpp ${USER-OMP_SOURCES_DIR}/domain_omp.cpp) - add_definitions(-DLMP_USER_OMP) + target_compile_definitions(lammps PRIVATE -DLMP_USER_OMP) set_property(GLOBAL PROPERTY "OMP_SOURCES" "${USER-OMP_SOURCES}") # detects styles which have USER-OMP version diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index a6cd20adbb..cfd187ed9d 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -69,12 +69,12 @@ if(PKG_USER-PLUMED) set(PLUMED_INSTALL_DIR ${INSTALL_DIR}) add_dependencies(lammps plumed_build) if(PLUMED_MODE STREQUAL "STATIC") - add_definitions(-D__PLUMED_WRAPPER_CXX=1) + target_compile_definitions(lammps PRIVATE -D__PLUMED_WRAPPER_CXX=1) target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed.a ${PLUMED_LINK_LIBS} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "SHARED") target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumed${CMAKE_SHARED_LIBRARY_SUFFIX} ${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX} ${CMAKE_DL_LIBS}) elseif(PLUMED_MODE STREQUAL "RUNTIME") - add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) + target_compile_definitions(lammps PRIVATE -D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_INSTALL_DIR}/lib/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) target_link_libraries(lammps PRIVATE ${PLUMED_INSTALL_DIR}/lib/libplumedWrapper.a -rdynamic ${CMAKE_DL_LIBS}) endif() set(PLUMED_INCLUDE_DIRS "${PLUMED_INSTALL_DIR}/include") @@ -82,12 +82,12 @@ if(PKG_USER-PLUMED) find_package(PkgConfig REQUIRED) pkg_check_modules(PLUMED REQUIRED plumed) if(PLUMED_MODE STREQUAL "STATIC") - add_definitions(-D__PLUMED_WRAPPER_CXX=1) + target_compile_definitions(lammps PRIVATE -D__PLUMED_WRAPPER_CXX=1) include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.static) elseif(PLUMED_MODE STREQUAL "SHARED") include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.shared) elseif(PLUMED_MODE STREQUAL "RUNTIME") - add_definitions(-D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_LIBDIR}/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) + target_compile_definitions(lammps PRIVATE -D__PLUMED_HAS_DLOPEN=1 -D__PLUMED_DEFAULT_KERNEL=${PLUMED_LIBDIR}/libplumedKernel${CMAKE_SHARED_LIBRARY_SUFFIX}) include(${PLUMED_LIBDIR}/plumed/src/lib/Plumed.cmake.runtime) endif() target_link_libraries(lammps PRIVATE ${PLUMED_LOAD}) diff --git a/cmake/Modules/Packages/USER-VTK.cmake b/cmake/Modules/Packages/USER-VTK.cmake index fb69f115b2..61defcbf82 100644 --- a/cmake/Modules/Packages/USER-VTK.cmake +++ b/cmake/Modules/Packages/USER-VTK.cmake @@ -1,6 +1,6 @@ if(PKG_USER-VTK) find_package(VTK REQUIRED NO_MODULE) include(${VTK_USE_FILE}) - add_definitions(-DLAMMPS_VTK) + target_compile_definitions(lammps PRIVATE -DLAMMPS_VTK) target_link_libraries(lammps PRIVATE ${VTK_LIBRARIES}) endif() -- GitLab From f2ab654662fbba0a43a3919d13bb48590d8d08a9 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 10:41:19 -0600 Subject: [PATCH 075/577] cmake: some include_directories() -> target_include_directories() --- cmake/CMakeLists.txt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index b1d90af045..aaafd9c3f6 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -165,7 +165,7 @@ endif() ###################################################### # packages with special compiler needs or external libs ###################################################### -include_directories(${LAMMPS_SOURCE_DIR}) +target_include_directories(lammps PRIVATE ${LAMMPS_SOURCE_DIR}) if(PKG_USER-ADIOS) # The search for ADIOS2 must come before MPI because @@ -200,7 +200,7 @@ else() enable_language(C) file(GLOB MPI_SOURCES ${LAMMPS_SOURCE_DIR}/STUBS/mpi.c) add_library(mpi_stubs STATIC ${MPI_SOURCES}) - include_directories(${LAMMPS_SOURCE_DIR}/STUBS) + target_include_directories(mpi_stubs PUBLIC ${LAMMPS_SOURCE_DIR}/STUBS) target_link_libraries(lammps PRIVATE mpi_stubs) endif() @@ -285,7 +285,7 @@ if(WITH_JPEG) find_package(JPEG REQUIRED) target_compile_definitions(lammps PRIVATE -DLAMMPS_JPEG) if(CMAKE_VERSION VERSION_LESS 3.12) - include_directories(${JPEG_INCLUDE_DIR}) + target_include_directories(lammps PRIVATE ${JPEG_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${JPEG_LIBRARIES}) else() target_link_libraries(lammps PRIVATE JPEG::JPEG) @@ -404,7 +404,7 @@ foreach(PKG ${DEFAULT_PACKAGES}) RegisterStyles(${${PKG}_SOURCES_DIR}) target_sources(lammps PRIVATE ${${PKG}_SOURCES}) - include_directories(${${PKG}_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${${PKG}_SOURCES_DIR}) endif() RegisterPackages(${${PKG}_SOURCES_DIR}) @@ -504,7 +504,7 @@ set(LAMMPS_STYLE_HEADERS_DIR ${CMAKE_CURRENT_BINARY_DIR}/styles) GenerateStyleHeaders(${LAMMPS_STYLE_HEADERS_DIR}) GeneratePackagesHeaders(${LAMMPS_STYLE_HEADERS_DIR}) -include_directories(${LAMMPS_STYLE_HEADERS_DIR}) +target_include_directories(lammps PRIVATE ${LAMMPS_STYLE_HEADERS_DIR}) ###################################### # Generate lmpinstalledpkgs.h -- GitLab From 31930139c6a5ffcb956ec7da462df330590b3a77 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 10:49:13 -0600 Subject: [PATCH 076/577] USER-SMD.cmake: use Eigen3 imported target --- cmake/Modules/Packages/USER-SMD.cmake | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cmake/Modules/Packages/USER-SMD.cmake b/cmake/Modules/Packages/USER-SMD.cmake index eed60ae8bd..9d2c48fe1d 100644 --- a/cmake/Modules/Packages/USER-SMD.cmake +++ b/cmake/Modules/Packages/USER-SMD.cmake @@ -15,7 +15,7 @@ if(PKG_USER-SMD) CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" ) ExternalProject_get_property(Eigen3_build SOURCE_DIR) - set(EIGEN3_INCLUDE_DIR ${SOURCE_DIR}) + target_include_directories(lammps ${SOURCE_DIR}) add_dependencies(lammps Eigen3_build) else() find_package(Eigen3 NO_MODULE) @@ -23,6 +23,6 @@ if(PKG_USER-SMD) if(NOT EIGEN3_FOUND) message(FATAL_ERROR "Eigen3 not found, help CMake to find it by setting EIGEN3_INCLUDE_DIR, or set DOWNLOAD_EIGEN3=ON to download it") endif() + target_link_libraries(lammps PRIVATE Eigen3::Eigen) endif() - include_directories(${EIGEN3_INCLUDE_DIR}) endif() -- GitLab From 9b244b14a6f00f14237e51b3124cda8b420d63a8 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 10:56:49 -0600 Subject: [PATCH 077/577] atc: needs lammps.h --- cmake/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index aaafd9c3f6..a93f1ee42a 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -465,6 +465,7 @@ if(PKG_USER-ATC) message(FATAL_ERROR "The USER-ATC Package is not compatible with -DLAMMPS_BIGBIG") endif() target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES}) + target_include_directories(atc PRIVATE ${LAMMPS_SOURCE_DIR}) endif() include(Packages/USER-H5MD) -- GitLab From 51eb865d6342ec32cd1262635a86d78802f75c7c Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:05:25 -0600 Subject: [PATCH 078/577] VORONOI.cmake: use VORO imported target --- cmake/Modules/FindVORO.cmake | 16 +++++++++++++--- cmake/Modules/Packages/VORONOI.cmake | 7 +++---- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindVORO.cmake b/cmake/Modules/FindVORO.cmake index b0cccbcd1d..3f0fe98ff1 100644 --- a/cmake/Modules/FindVORO.cmake +++ b/cmake/Modules/FindVORO.cmake @@ -10,13 +10,23 @@ find_path(VORO_INCLUDE_DIR voro++.hh PATH_SUFFIXES voro++) find_library(VORO_LIBRARY NAMES voro++) -set(VORO_LIBRARIES ${VORO_LIBRARY}) -set(VORO_INCLUDE_DIRS ${VORO_INCLUDE_DIR}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set VORO_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(VORO DEFAULT_MSG VORO_LIBRARY VORO_INCLUDE_DIR) +# Copy the results to the output variables and target. +if(VORO_FOUND) + set(VORO_LIBRARIES ${VORO_LIBRARY}) + set(VORO_INCLUDE_DIRS ${VORO_INCLUDE_DIR}) + + if(NOT TARGET VORO::VORO) + add_library(VORO::VORO UNKNOWN IMPORTED) + set_target_properties(VORO::VORO PROPERTIES + IMPORTED_LOCATION "${VORO_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${VORO_INCLUDE_DIR}") + endif() +endif() + mark_as_advanced(VORO_INCLUDE_DIR VORO_LIBRARY ) diff --git a/cmake/Modules/Packages/VORONOI.cmake b/cmake/Modules/Packages/VORONOI.cmake index d2bb185228..e7f2b6b46d 100644 --- a/cmake/Modules/Packages/VORONOI.cmake +++ b/cmake/Modules/Packages/VORONOI.cmake @@ -29,15 +29,14 @@ if(PKG_VORONOI) BUILD_BYPRODUCTS /src/libvoro++.a ) ExternalProject_get_property(voro_build SOURCE_DIR) - set(VORO_LIBRARIES ${SOURCE_DIR}/src/libvoro++.a) - set(VORO_INCLUDE_DIRS ${SOURCE_DIR}/src) + target_link_libraries(lammps PRIVATE ${SOURCE_DIR}/src/libvoro++.a) + target_include_directories(lammps PRIVATE ${SOURCE_DIR}/src) add_dependencies(lammps voro_build) else() find_package(VORO) if(NOT VORO_FOUND) message(FATAL_ERROR "Voro++ library not found. Help CMake to find it by setting VORO_LIBRARY and VORO_INCLUDE_DIR, or set DOWNLOAD_VORO=ON to download it") endif() + target_link_libraries(lammps PRIVATE VORO::VORO) endif() - include_directories(${VORO_INCLUDE_DIRS}) - target_link_libraries(lammps PRIVATE ${VORO_LIBRARIES}) endif() -- GitLab From 4736402dd944d773a081fbf7cc6933010644da64 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:07:45 -0600 Subject: [PATCH 079/577] cmake: atc needs mpi itself --- cmake/CMakeLists.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index a93f1ee42a..0001f37fce 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -202,6 +202,7 @@ else() add_library(mpi_stubs STATIC ${MPI_SOURCES}) target_include_directories(mpi_stubs PUBLIC ${LAMMPS_SOURCE_DIR}/STUBS) target_link_libraries(lammps PRIVATE mpi_stubs) + add_library(MPI::MPI_CXX ALIAS mpi_stubs) endif() set(LAMMPS_SIZES "smallbig" CACHE STRING "LAMMPS integer sizes (smallsmall: all 32-bit, smallbig: 64-bit #atoms #timesteps, bigbig: also 64-bit imageint, 64-bit atom ids)") @@ -464,7 +465,7 @@ if(PKG_USER-ATC) if(LAMMPS_SIZES STREQUAL BIGBIG) message(FATAL_ERROR "The USER-ATC Package is not compatible with -DLAMMPS_BIGBIG") endif() - target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES}) + target_link_libraries(atc PRIVATE ${LAPACK_LIBRARIES} MPI::MPI_CXX) target_include_directories(atc PRIVATE ${LAMMPS_SOURCE_DIR}) endif() -- GitLab From 33a57ed21592615a752021c789df4db142747edd Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:36:21 -0600 Subject: [PATCH 080/577] cmake: some more include_directories() -> target_include_directories() --- cmake/Modules/MPI4WIN.cmake | 2 +- cmake/Modules/Packages/CORESHELL.cmake | 2 +- cmake/Modules/Packages/GPU.cmake | 2 +- cmake/Modules/Packages/KIM.cmake | 2 +- cmake/Modules/Packages/KOKKOS.cmake | 4 ++-- cmake/Modules/Packages/KSPACE.cmake | 2 +- cmake/Modules/Packages/MESSAGE.cmake | 2 +- cmake/Modules/Packages/OPT.cmake | 2 +- cmake/Modules/Packages/PYTHON.cmake | 2 +- cmake/Modules/Packages/QEQ.cmake | 2 +- cmake/Modules/Packages/USER-H5MD.cmake | 1 - cmake/Modules/Packages/USER-INTEL.cmake | 2 +- cmake/Modules/Packages/USER-OMP.cmake | 2 +- cmake/Modules/Packages/USER-PLUMED.cmake | 2 +- cmake/Modules/Packages/USER-SDPD.cmake | 2 +- 15 files changed, 15 insertions(+), 16 deletions(-) diff --git a/cmake/Modules/MPI4WIN.cmake b/cmake/Modules/MPI4WIN.cmake index a02adca77d..4447289668 100644 --- a/cmake/Modules/MPI4WIN.cmake +++ b/cmake/Modules/MPI4WIN.cmake @@ -17,7 +17,7 @@ endif() ExternalProject_get_property(mpi4win_build SOURCE_DIR) target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX) -include_directories("${SOURCE_DIR}/include") +target_include_directories(lammps PRIVATE "${SOURCE_DIR}/include") set(MPI4WIN_LIBRARIES "${SOURCE_DIR}/lib/libmpi.a") add_dependencies(lammps mpi4win_build) set(LAMMPS_USE_MPI4WIN ON) diff --git a/cmake/Modules/Packages/CORESHELL.cmake b/cmake/Modules/Packages/CORESHELL.cmake index 2afe2b8c1b..e550b1989f 100644 --- a/cmake/Modules/Packages/CORESHELL.cmake +++ b/cmake/Modules/Packages/CORESHELL.cmake @@ -9,5 +9,5 @@ if(PKG_CORESHELL) get_property(CORESHELL_SOURCES GLOBAL PROPERTY CORESHELL_SOURCES) target_sources(lammps PRIVATE ${CORESHELL_SOURCES}) - include_directories(${CORESHELL_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${CORESHELL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/GPU.cmake b/cmake/Modules/Packages/GPU.cmake index 95bb525dd5..cd359068e7 100644 --- a/cmake/Modules/Packages/GPU.cmake +++ b/cmake/Modules/Packages/GPU.cmake @@ -193,5 +193,5 @@ if(PKG_GPU) get_property(GPU_SOURCES GLOBAL PROPERTY GPU_SOURCES) target_sources(lammps PRIVATE ${GPU_SOURCES}) - include_directories(${GPU_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${GPU_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/KIM.cmake b/cmake/Modules/Packages/KIM.cmake index 7d349f496b..5a4b12956e 100644 --- a/cmake/Modules/Packages/KIM.cmake +++ b/cmake/Modules/Packages/KIM.cmake @@ -62,5 +62,5 @@ if(PKG_KIM) find_package(KIM-API ${KIM-API_MIN_VERSION} REQUIRED) endif() target_link_libraries(lammps PRIVATE "${KIM-API_LDFLAGS}") - include_directories(${KIM-API_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${KIM-API_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/KOKKOS.cmake b/cmake/Modules/Packages/KOKKOS.cmake index 34c924790e..083b55840c 100644 --- a/cmake/Modules/Packages/KOKKOS.cmake +++ b/cmake/Modules/Packages/KOKKOS.cmake @@ -15,7 +15,7 @@ if(PKG_KOKKOS) ${LAMMPS_LIB_KOKKOS_SRC_DIR}/containers/src ${LAMMPS_LIB_KOKKOS_SRC_DIR}/algorithms/src ${LAMMPS_LIB_KOKKOS_BIN_DIR}) - include_directories(${Kokkos_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${Kokkos_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE kokkos) endif() target_compile_definitions(lammps PRIVATE -DLMP_KOKKOS) @@ -70,5 +70,5 @@ if(PKG_KOKKOS) get_property(KOKKOS_PKG_SOURCES GLOBAL PROPERTY KOKKOS_PKG_SOURCES) target_sources(lammps PRIVATE ${KOKKOS_PKG_SOURCES}) - include_directories(${KOKKOS_PKG_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${KOKKOS_PKG_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/KSPACE.cmake b/cmake/Modules/Packages/KSPACE.cmake index e2a42f3981..184a70f746 100644 --- a/cmake/Modules/Packages/KSPACE.cmake +++ b/cmake/Modules/Packages/KSPACE.cmake @@ -41,7 +41,7 @@ if(PKG_KSPACE) if(FFT_MKL_THREADS) target_compile_definitions(lammps PRIVATE -DFFT_MKL_THREADS) endif() - include_directories(${MKL_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${MKL_INCLUDE_DIRS}) target_link_libraries(lammps PRIVATE ${MKL_LIBRARIES}) else() # last option is KISSFFT diff --git a/cmake/Modules/Packages/MESSAGE.cmake b/cmake/Modules/Packages/MESSAGE.cmake index c28c50c507..54d9f3eef7 100644 --- a/cmake/Modules/Packages/MESSAGE.cmake +++ b/cmake/Modules/Packages/MESSAGE.cmake @@ -28,5 +28,5 @@ if(PKG_MESSAGE) endif() target_link_libraries(lammps PRIVATE cslib) - include_directories(${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src) + target_include_directories(lammps PRIVATE ${LAMMPS_LIB_SOURCE_DIR}/message/cslib/src) endif() diff --git a/cmake/Modules/Packages/OPT.cmake b/cmake/Modules/Packages/OPT.cmake index 02e3877c59..5d006bfd58 100644 --- a/cmake/Modules/Packages/OPT.cmake +++ b/cmake/Modules/Packages/OPT.cmake @@ -9,5 +9,5 @@ if(PKG_OPT) get_property(OPT_SOURCES GLOBAL PROPERTY OPT_SOURCES) target_sources(lammps PRIVATE ${OPT_SOURCES}) - include_directories(${OPT_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${OPT_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/PYTHON.cmake b/cmake/Modules/Packages/PYTHON.cmake index 4611fddb98..b2451ebbdf 100644 --- a/cmake/Modules/Packages/PYTHON.cmake +++ b/cmake/Modules/Packages/PYTHON.cmake @@ -1,6 +1,6 @@ if(PKG_PYTHON) find_package(PythonLibs REQUIRED) target_compile_definitions(lammps PRIVATE -DLMP_PYTHON) - include_directories(${PYTHON_INCLUDE_DIR}) + target_include_directories(lammps PRIVATE ${PYTHON_INCLUDE_DIR}) target_link_libraries(lammps PRIVATE ${PYTHON_LIBRARY}) endif() diff --git a/cmake/Modules/Packages/QEQ.cmake b/cmake/Modules/Packages/QEQ.cmake index 9b151c2610..d69fb23440 100644 --- a/cmake/Modules/Packages/QEQ.cmake +++ b/cmake/Modules/Packages/QEQ.cmake @@ -16,5 +16,5 @@ if(PKG_QEQ) get_property(QEQ_SOURCES GLOBAL PROPERTY QEQ_SOURCES) target_sources(lammps PRIVATE ${QEQ_SOURCES}) - include_directories(${QEQ_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${QEQ_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-H5MD.cmake b/cmake/Modules/Packages/USER-H5MD.cmake index 1e3fcf82ce..cf5623f46d 100644 --- a/cmake/Modules/Packages/USER-H5MD.cmake +++ b/cmake/Modules/Packages/USER-H5MD.cmake @@ -4,5 +4,4 @@ if(PKG_USER-H5MD) find_package(HDF5 REQUIRED) target_link_libraries(h5md PRIVATE ${HDF5_LIBRARIES}) target_include_directories(h5md PRIVATE ${HDF5_INCLUDE_DIRS}) - include_directories(${HDF5_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-INTEL.cmake b/cmake/Modules/Packages/USER-INTEL.cmake index 96a897297f..d81f793f50 100644 --- a/cmake/Modules/Packages/USER-INTEL.cmake +++ b/cmake/Modules/Packages/USER-INTEL.cmake @@ -109,5 +109,5 @@ if(PKG_USER-INTEL) endif() target_sources(lammps PRIVATE ${USER-INTEL_SOURCES}) - include_directories(${USER-INTEL_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${USER-INTEL_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-OMP.cmake b/cmake/Modules/Packages/USER-OMP.cmake index 91f0467a17..42f91495d5 100644 --- a/cmake/Modules/Packages/USER-OMP.cmake +++ b/cmake/Modules/Packages/USER-OMP.cmake @@ -38,5 +38,5 @@ if(PKG_USER-OMP) endif() target_sources(lammps PRIVATE ${USER-OMP_SOURCES}) - include_directories(${USER-OMP_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${USER-OMP_SOURCES_DIR}) endif() diff --git a/cmake/Modules/Packages/USER-PLUMED.cmake b/cmake/Modules/Packages/USER-PLUMED.cmake index cfd187ed9d..75b2db2f93 100644 --- a/cmake/Modules/Packages/USER-PLUMED.cmake +++ b/cmake/Modules/Packages/USER-PLUMED.cmake @@ -92,5 +92,5 @@ if(PKG_USER-PLUMED) endif() target_link_libraries(lammps PRIVATE ${PLUMED_LOAD}) endif() - include_directories(${PLUMED_INCLUDE_DIRS}) + target_include_directories(lammps PRIVATE ${PLUMED_INCLUDE_DIRS}) endif() diff --git a/cmake/Modules/Packages/USER-SDPD.cmake b/cmake/Modules/Packages/USER-SDPD.cmake index 1105fbd7ce..750194bcc6 100644 --- a/cmake/Modules/Packages/USER-SDPD.cmake +++ b/cmake/Modules/Packages/USER-SDPD.cmake @@ -11,5 +11,5 @@ if(PKG_USER-SDPD) endif() set_property(GLOBAL PROPERTY FIX "${hlist}") - include_directories(${USER-SDPD_SOURCES_DIR}) + target_include_directories(lammps PRIVATE ${USER-SDPD_SOURCES_DIR}) endif() -- GitLab From d8b6d10f3b9d65f99232980510011ace2db068a6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:42:36 -0600 Subject: [PATCH 081/577] MSCG.cmake: create an use imported target --- cmake/Modules/FindMSCG.cmake | 16 +++++++++++++--- cmake/Modules/Packages/MSCG.cmake | 12 ++++++++---- 2 files changed, 21 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindMSCG.cmake b/cmake/Modules/FindMSCG.cmake index 311ff78038..b301303dbe 100644 --- a/cmake/Modules/FindMSCG.cmake +++ b/cmake/Modules/FindMSCG.cmake @@ -10,13 +10,23 @@ find_path(MSCG_INCLUDE_DIR mscg.h PATH_SUFFIXES mscg) find_library(MSCG_LIBRARY NAMES mscg) -set(MSCG_LIBRARIES ${MSCG_LIBRARY}) -set(MSCG_INCLUDE_DIRS ${MSCG_INCLUDE_DIR}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set MSCG_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(MSCG DEFAULT_MSG MSCG_LIBRARY MSCG_INCLUDE_DIR) +# Copy the results to the output variables and target. +if(MSCG_FOUND) + set(MSCG_LIBRARIES ${MSCG_LIBRARY}) + set(MSCG_INCLUDE_DIRS ${MSCG_INCLUDE_DIR}) + + if(NOT TARGET MSCG::MSCG) + add_library(MSCG::MSCG UNKNOWN IMPORTED) + set_target_properties(MSCG::MSCG PROPERTIES + IMPORTED_LOCATION "${MSCG_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${MSCG_INCLUDE_DIR}") + endif() +endif() + mark_as_advanced(MSCG_INCLUDE_DIR MSCG_LIBRARY ) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 2c63e69fa7..750a1a8c37 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -29,12 +29,17 @@ if(PKG_MSCG) BUILD_BYPRODUCTS /libmscg.a ) ExternalProject_get_property(mscg_build BINARY_DIR) - set(MSCG_LIBRARIES ${BINARY_DIR}/libmscg.a) ExternalProject_get_property(mscg_build SOURCE_DIR) set(MSCG_INCLUDE_DIRS ${SOURCE_DIR}/src) + if(NOT TARGET MSCG::MSCG) + add_library(MSCG::MSCG UNKNOWN IMPORTED) + set_target_properties(MSCG::MSCG PROPERTIES + IMPORTED_LOCATION "${BINARY_DIR}/libmscg.a" + INTERFACE_INCLUDE_DIRECTORIES "${MSCG_INCLUDE_DIRS}") + endif() add_dependencies(lammps mscg_build) if(NOT LAPACK_FOUND) - file(MAKE_DIRECTORY ${MSCG_INCLUDE_DIRS}) + file(MAKE_DIRECTORY ) add_dependencies(mscg_build linalg) endif() else() @@ -43,6 +48,5 @@ if(PKG_MSCG) message(FATAL_ERROR "MSCG not found, help CMake to find it by setting MSCG_LIBRARY and MSCG_INCLUDE_DIRS, or set DOWNLOAD_MSCG=ON to download it") endif() endif() - target_link_libraries(lammps PRIVATE ${MSCG_LIBRARIES} GSL::gsl ${LAPACK_LIBRARIES}) - include_directories(${MSCG_INCLUDE_DIRS}) + target_link_libraries(lammps PRIVATE MSCG::MSCG GSL::gsl ${LAPACK_LIBRARIES}) endif() -- GitLab From 72c94f0fbf7c70c18fb44820247fe2b83667efb6 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 11:49:24 -0600 Subject: [PATCH 082/577] USER-SCAFACOS.cmake: use imported pkg-config target --- cmake/Modules/Packages/USER-SCAFACOS.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/Packages/USER-SCAFACOS.cmake b/cmake/Modules/Packages/USER-SCAFACOS.cmake index ebd750c04b..6725472c07 100644 --- a/cmake/Modules/Packages/USER-SCAFACOS.cmake +++ b/cmake/Modules/Packages/USER-SCAFACOS.cmake @@ -46,7 +46,7 @@ if(PKG_USER-SCAFACOS) ) ExternalProject_get_property(scafacos_build INSTALL_DIR) set(SCAFACOS_BUILD_DIR ${INSTALL_DIR}) - set(SCAFACOS_INCLUDE_DIRS ${SCAFACOS_BUILD_DIR}/include) + target_include_directories(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/include) add_dependencies(lammps scafacos_build) # list and order from pkg_config file of ScaFaCoS build target_link_libraries(lammps PRIVATE ${SCAFACOS_BUILD_DIR}/lib/libfcs.a) @@ -69,8 +69,7 @@ if(PKG_USER-SCAFACOS) target_link_libraries(lammps PRIVATE ${MPI_C_LIBRARIES}) else() find_package(PkgConfig REQUIRED) - pkg_check_modules(SCAFACOS REQUIRED scafacos) - target_link_libraries(lammps PRIVATE ${SCAFACOS_LDFLAGS}) + pkg_check_modules(SCAFACOS REQUIRED IMPORTED_TARGET scafacos) + target_link_libraries(lammps PRIVATE PkgConfig::SCAFACOS) endif() - include_directories(${SCAFACOS_INCLUDE_DIRS}) endif() -- GitLab From d19f112c754e8345813e23d1743bca837c87d27b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 12:18:10 -0600 Subject: [PATCH 083/577] MSCG.cmake: fix up imported target --- cmake/Modules/Packages/MSCG.cmake | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/cmake/Modules/Packages/MSCG.cmake b/cmake/Modules/Packages/MSCG.cmake index 750a1a8c37..f4bac7d422 100644 --- a/cmake/Modules/Packages/MSCG.cmake +++ b/cmake/Modules/Packages/MSCG.cmake @@ -31,15 +31,11 @@ if(PKG_MSCG) ExternalProject_get_property(mscg_build BINARY_DIR) ExternalProject_get_property(mscg_build SOURCE_DIR) set(MSCG_INCLUDE_DIRS ${SOURCE_DIR}/src) - if(NOT TARGET MSCG::MSCG) - add_library(MSCG::MSCG UNKNOWN IMPORTED) - set_target_properties(MSCG::MSCG PROPERTIES - IMPORTED_LOCATION "${BINARY_DIR}/libmscg.a" - INTERFACE_INCLUDE_DIRECTORIES "${MSCG_INCLUDE_DIRS}") - endif() + target_include_directories(lammps PRIVATE ${MSCG_INCLUDE_DIRS}) + target_link_libraries(lammps PRIVATE "${BINARY_DIR}/libmscg.a") add_dependencies(lammps mscg_build) if(NOT LAPACK_FOUND) - file(MAKE_DIRECTORY ) + file(MAKE_DIRECTORY ${MSCG_INCLUDE_DIRS}) add_dependencies(mscg_build linalg) endif() else() @@ -47,6 +43,7 @@ if(PKG_MSCG) if(NOT MSCG_FOUND) message(FATAL_ERROR "MSCG not found, help CMake to find it by setting MSCG_LIBRARY and MSCG_INCLUDE_DIRS, or set DOWNLOAD_MSCG=ON to download it") endif() + target_link_libraries(lammps PRIVATE MSCG::MSCG) endif() - target_link_libraries(lammps PRIVATE MSCG::MSCG GSL::gsl ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE GSL::gsl ${LAPACK_LIBRARIES}) endif() -- GitLab From f5279a291e93195054e4099ef0fec0ccb5f61093 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 12:23:39 -0600 Subject: [PATCH 084/577] USER-QUIP.cmake: create and use imported target --- cmake/Modules/FindQUIP.cmake | 13 +++++++++++-- cmake/Modules/Packages/USER-QUIP.cmake | 2 +- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/cmake/Modules/FindQUIP.cmake b/cmake/Modules/FindQUIP.cmake index b6d87d11fa..277cfae49e 100644 --- a/cmake/Modules/FindQUIP.cmake +++ b/cmake/Modules/FindQUIP.cmake @@ -7,12 +7,21 @@ find_library(QUIP_LIBRARY NAMES quip) -set(QUIP_LIBRARIES ${QUIP_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set QUIP_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(QUIP DEFAULT_MSG QUIP_LIBRARY) +# Copy the results to the output variables and target. +if(QUIP_FOUND) + set(QUIP_LIBRARIES ${QUIP_LIBRARY}) + + if(NOT TARGET QUIP::QUIP) + add_library(QUIP::QUIP UNKNOWN IMPORTED) + set_target_properties(QUIP::QUIP PROPERTIES + IMPORTED_LOCATION "${QUIP_LIBRARY}") + endif() +endif() + mark_as_advanced(QUIP_LIBRARY) diff --git a/cmake/Modules/Packages/USER-QUIP.cmake b/cmake/Modules/Packages/USER-QUIP.cmake index 52ba7e9c47..4f41f9ef98 100644 --- a/cmake/Modules/Packages/USER-QUIP.cmake +++ b/cmake/Modules/Packages/USER-QUIP.cmake @@ -1,5 +1,5 @@ if(PKG_USER-QUIP) enable_language(Fortran) find_package(QUIP REQUIRED) - target_link_libraries(lammps PRIVATE ${LAPACK_LIBRARIES}) + target_link_libraries(lammps PRIVATE QUIP::QUIP ${LAPACK_LIBRARIES}) endif() -- GitLab From 99d4a226b5d0f74927b118dbd1bb4b90edaa7606 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 12:33:36 -0600 Subject: [PATCH 085/577] USER-NETCDF.cmake: create and use imported targets --- cmake/Modules/FindNetCDF.cmake | 16 ++++++++++++++-- cmake/Modules/FindPNetCDF.cmake | 9 +++++++++ cmake/Modules/Packages/USER-NETCDF.cmake | 6 ++---- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/cmake/Modules/FindNetCDF.cmake b/cmake/Modules/FindNetCDF.cmake index 2a992b6b3b..7f0ee93520 100644 --- a/cmake/Modules/FindNetCDF.cmake +++ b/cmake/Modules/FindNetCDF.cmake @@ -112,11 +112,23 @@ NetCDF_check_interface (F90 netcdf.mod netcdff) #export accumulated results to internal varS that rest of project can depend on list (APPEND NetCDF_libs "${NETCDF_C_LIBRARIES}") -set (NETCDF_LIBRARIES ${NetCDF_libs}) -set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) # handle the QUIETLY and REQUIRED arguments and set NETCDF_FOUND to TRUE if # all listed variables are TRUE include (FindPackageHandleStandardArgs) find_package_handle_standard_args (NetCDF DEFAULT_MSG NETCDF_LIBRARIES NETCDF_INCLUDE_DIRS NETCDF_HAS_INTERFACES) + +# Copy the results to the output variables and target. +if(NetCDF_FOUND) + set (NETCDF_LIBRARIES ${NetCDF_libs}) + set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) + + if(NOT TARGET NetCDF::NetCDF) + add_library(NetCDF::NetCDF UNKNOWN IMPORTED) + set_target_properties(NetCDF::NetCDF PROPERTIES + IMPORTED_LOCATION "${NETCDF_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_includes}" + INTERFACE_LINK_LIBRARIES "${NETCDF_LIBRARIES}") + endif() +endif() diff --git a/cmake/Modules/FindPNetCDF.cmake b/cmake/Modules/FindPNetCDF.cmake index bc3a5f9538..e501e9af49 100644 --- a/cmake/Modules/FindPNetCDF.cmake +++ b/cmake/Modules/FindPNetCDF.cmake @@ -53,3 +53,12 @@ include (FindPackageHandleStandardArgs) find_package_handle_standard_args (PNetCDF DEFAULT_MSG PNETCDF_LIBRARIES PNETCDF_INCLUDES) mark_as_advanced (PNETCDF_LIBRARIES PNETCDF_INCLUDES) + +if(PNetCDF_FOUND) + if(NOT TARGET PNetCDF::PNetCDF) + add_library(PNetCDF::PNetCDF UNKNOWN IMPORTED) + set_target_properties(PNetCDF::PNetCDF PROPERTIES + IMPORTED_LOCATION "${PNETCDF_LIBRARIES}" + INTERFACE_INCLUDE_DIRECTORIES "${PNETCDF_INCLUDES}") + endif() +endif() diff --git a/cmake/Modules/Packages/USER-NETCDF.cmake b/cmake/Modules/Packages/USER-NETCDF.cmake index 2c12d2b799..a149c7357d 100644 --- a/cmake/Modules/Packages/USER-NETCDF.cmake +++ b/cmake/Modules/Packages/USER-NETCDF.cmake @@ -9,14 +9,12 @@ if(PKG_USER-NETCDF) endif(NETCDF_FOUND) if(NETCDF_FOUND) - include_directories(${NETCDF_INCLUDE_DIRS}) - target_link_libraries(lammps PRIVATE ${NETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE NetCDF::NetCDF) target_compile_definitions(lammps PRIVATE -DLMP_HAS_NETCDF) endif(NETCDF_FOUND) if(PNETCDF_FOUND) - include_directories(${PNETCDF_INCLUDES}) - target_link_libraries(lammps PRIVATE ${PNETCDF_LIBRARIES}) + target_link_libraries(lammps PRIVATE PNetCDF::PNetCDF) target_compile_definitions(lammps PRIVATE -DLMP_HAS_PNETCDF) endif(PNETCDF_FOUND) -- GitLab From 5eb77f2e9a2c3045f0b5c080ce7ef07a6eb903d2 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 14:29:14 -0600 Subject: [PATCH 086/577] FindNetCDF.cmake: fix target --- cmake/Modules/FindNetCDF.cmake | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/cmake/Modules/FindNetCDF.cmake b/cmake/Modules/FindNetCDF.cmake index 7f0ee93520..5c8caa9208 100644 --- a/cmake/Modules/FindNetCDF.cmake +++ b/cmake/Modules/FindNetCDF.cmake @@ -112,6 +112,8 @@ NetCDF_check_interface (F90 netcdf.mod netcdff) #export accumulated results to internal varS that rest of project can depend on list (APPEND NetCDF_libs "${NETCDF_C_LIBRARIES}") +set (NETCDF_LIBRARIES ${NetCDF_libs}) +set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) # handle the QUIETLY and REQUIRED arguments and set NETCDF_FOUND to TRUE if # all listed variables are TRUE @@ -121,14 +123,11 @@ find_package_handle_standard_args (NetCDF # Copy the results to the output variables and target. if(NetCDF_FOUND) - set (NETCDF_LIBRARIES ${NetCDF_libs}) - set (NETCDF_INCLUDE_DIRS ${NetCDF_includes}) - if(NOT TARGET NetCDF::NetCDF) add_library(NetCDF::NetCDF UNKNOWN IMPORTED) set_target_properties(NetCDF::NetCDF PROPERTIES IMPORTED_LOCATION "${NETCDF_LIBRARY}" - INTERFACE_INCLUDE_DIRECTORIES "${NetCDF_includes}" + INTERFACE_INCLUDE_DIRECTORIES "${NETCDF_INCLUDE_DIRS}" INTERFACE_LINK_LIBRARIES "${NETCDF_LIBRARIES}") endif() endif() -- GitLab From 0da108f06fe2b7372a0ade40378b4368edbaa257 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Tue, 24 Mar 2020 14:50:38 -0600 Subject: [PATCH 087/577] cmake: remove last include_directories() call --- cmake/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 0001f37fce..3569ffc555 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -188,7 +188,6 @@ if(BUILD_MPI) include(MPI4WIN) else() find_package(MPI REQUIRED) - include_directories(${MPI_CXX_INCLUDE_PATH}) target_compile_definitions(lammps PRIVATE -DMPICH_SKIP_MPICXX -DOMPI_SKIP_MPICXX=1) target_link_libraries(lammps PUBLIC MPI::MPI_CXX) option(LAMMPS_LONGLONG_TO_LONG "Workaround if your system or MPI version does not recognize 'long long' data types" OFF) -- GitLab From b8464da71ffbe6c1697b2c2071924d75c2ea30d0 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 07:45:21 -0600 Subject: [PATCH 088/577] cmake: remove FindLAMMPS.cmake --- cmake/CMakeLists.txt | 2 -- cmake/FindLAMMPS.cmake.in | 48 --------------------------------------- 2 files changed, 50 deletions(-) delete mode 100644 cmake/FindLAMMPS.cmake.in diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 3569ffc555..02d7b50f1b 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -584,8 +584,6 @@ if(BUILD_LIB) install(FILES ${LAMMPS_CXX_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps) configure_file(pkgconfig/liblammps.pc.in ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) - configure_file(FindLAMMPS.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake @ONLY) - install(FILES ${CMAKE_CURRENT_BINARY_DIR}/FindLAMMPS${LAMMPS_LIB_SUFFIX}.cmake DESTINATION ${CMAKE_INSTALL_DATADIR}/cmake/Modules) endif() if(BUILD_EXE) diff --git a/cmake/FindLAMMPS.cmake.in b/cmake/FindLAMMPS.cmake.in deleted file mode 100644 index 586df83c2d..0000000000 --- a/cmake/FindLAMMPS.cmake.in +++ /dev/null @@ -1,48 +0,0 @@ -# - Find liblammps -# Find the native liblammps headers and libraries. -# -# The following variables will set: -# LAMMPS_INCLUDE_DIRS - where to find lammps/library.h, etc. -# LAMMPS_LIBRARIES - List of libraries when using lammps. -# LAMMPS_API_DEFINES - lammps library api defines -# LAMMPS_VERSION - lammps library version -# LAMMPS_FOUND - True if liblammps found. -# -# In addition a LAMMPS::LAMMPS imported target is getting created. -# -# 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. -# - -find_package(PkgConfig) - -pkg_check_modules(PC_LAMMPS liblammps@LAMMPS_LIB_SUFFIX@) -find_path(LAMMPS_INCLUDE_DIR lammps/library.h HINTS ${PC_LAMMPS_INCLUDE_DIRS} @CMAKE_INSTALL_FULL_INCLUDEDIR@) - -set(LAMMPS_VERSION @LAMMPS_VERSION@) -set(LAMMPS_API_DEFINES @LAMMPS_API_DEFINES@) - -find_library(LAMMPS_LIBRARY NAMES lammps@LAMMPS_LIB_SUFFIX@ HINTS ${PC_LAMMPS_LIBRARY_DIRS} @CMAKE_INSTALL_FULL_LIBDIR@) - -set(LAMMPS_INCLUDE_DIRS "${LAMMPS_INCLUDE_DIR}") -set(LAMMPS_LIBRARIES "${LAMMPS_LIBRARY}") - -include(FindPackageHandleStandardArgs) -# handle the QUIETLY and REQUIRED arguments and set LAMMPS_FOUND to TRUE -# if all listed variables are TRUE -find_package_handle_standard_args(LAMMPS REQUIRED_VARS LAMMPS_LIBRARY LAMMPS_INCLUDE_DIR VERSION_VAR LAMMPS_VERSION) - -mark_as_advanced(LAMMPS_INCLUDE_DIR LAMMPS_LIBRARY) - -if(LAMMPS_FOUND AND NOT TARGET LAMMPS::LAMMPS) - add_library(LAMMPS::LAMMPS UNKNOWN IMPORTED) - set_target_properties(LAMMPS::LAMMPS PROPERTIES IMPORTED_LOCATION "${LAMMPS_LIBRARY}" INTERFACE_INCLUDE_DIRECTORIES "${LAMMPS_INCLUDE_DIR}" INTERFACE_COMPILE_DEFINITIONS "${LAMMPS_API_DEFINES}") -endif() -- GitLab From 0e9f65e0219b86d959ba66c948a6951c8003d80b Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 08:43:57 -0600 Subject: [PATCH 089/577] cmake: add exported target --- cmake/CMakeLists.txt | 9 +++++++-- cmake/LAMMPSConfig.cmake.in | 5 +++++ cmake/pkgconfig/liblammps.pc.in | 8 +------- 3 files changed, 13 insertions(+), 9 deletions(-) create mode 100644 cmake/LAMMPSConfig.cmake.in diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 02d7b50f1b..97bb00e250 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -26,7 +26,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/Modules) include(LAMMPSUtils) -get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h LAMMPS_VERSION) +get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h PROJECT_VERSION) include(PreventInSourceBuilds) @@ -579,11 +579,16 @@ if(BUILD_LIB) set_target_properties(lammps PROPERTIES OUTPUT_NAME lammps${LAMMPS_LIB_SUFFIX}) set_target_properties(lammps PROPERTIES SOVERSION ${SOVERSION}) - install(TARGETS lammps LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS lammps EXPORT LAMMPS_Targets LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}) install(FILES ${LAMMPS_SOURCE_DIR}/library.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps) install(FILES ${LAMMPS_CXX_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lammps) configure_file(pkgconfig/liblammps.pc.in ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblammps${LAMMPS_LIB_SUFFIX}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + install(EXPORT LAMMPS_Targets FILE LAMMPS_Targets.cmake NAMESPACE LAMMPS:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LAMMPS) + include(CMakePackageConfigHelpers) + configure_file(LAMMPSConfig.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfig.cmake @ONLY) + write_basic_package_version_file("LAMMPSConfigVersion.cmake" VERSION ${PROJECT_VERSION} COMPATIBILITY ExactVersion) + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/LAMMPSConfigVersion.cmake" DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/LAMMPS) endif() if(BUILD_EXE) diff --git a/cmake/LAMMPSConfig.cmake.in b/cmake/LAMMPSConfig.cmake.in new file mode 100644 index 0000000000..0dacfc2089 --- /dev/null +++ b/cmake/LAMMPSConfig.cmake.in @@ -0,0 +1,5 @@ +include(CMakeFindDependencyMacro) +if(@BUILD_MPI@) + find_dependency(MPI REQUIRED CXX) +endif() +include("${CMAKE_CURRENT_LIST_DIR}/LAMMPS_Targets.cmake") diff --git a/cmake/pkgconfig/liblammps.pc.in b/cmake/pkgconfig/liblammps.pc.in index a89f992c4a..96dab89161 100644 --- a/cmake/pkgconfig/liblammps.pc.in +++ b/cmake/pkgconfig/liblammps.pc.in @@ -18,12 +18,6 @@ # myapp_CFLAGS = $(LAMMPS_CFLAGS) # myapp_LDADD = $(LAMMPS_LIBS) -# Use this in CMake: -# CMakeLists.txt: -# find_package(PkgConfig) -# pkg_check_modules(LAMMPS IMPORTED_TARGET lammps) -# target_link_libraries( PRIVATE PkgConfig::LAMMPS) - prefix=@CMAKE_INSTALL_PREFIX@ libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ @@ -31,7 +25,7 @@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: liblammps@LAMMPS_MACHINE@ Description: Large-scale Atomic/Molecular Massively Parallel Simulator Library URL: http://lammps.sandia.gov -Version: @LAMMPS_VERSION@ +Version: @PROJECT_VERSION@ Requires: Libs: -L${libdir} -llammps@LAMMPS_LIB_SUFFIX@ Libs.private: -lm -- GitLab From ee3249676e726d5173d8b1efdf1f63c6b72ea2e3 Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 09:09:59 -0600 Subject: [PATCH 090/577] cmake: use OpenMP imported target --- cmake/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 97bb00e250..befbe4ecda 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -255,8 +255,7 @@ if(BUILD_OMP) if(NOT HAVE_OMP_H_INCLUDE) message(FATAL_ERROR "Cannot find required 'omp.h' header file") endif() - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") + target_link_libraries(lammps PRIVATE OpenMP::OpenMP_CXX) endif() if(PKG_MSCG OR PKG_USER-ATC OR PKG_USER-AWPMD OR PKG_USER-QUIP OR PKG_LATTE) -- GitLab From 58c9c4c64bc02d279b163cfb766ca6a4060f107d Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 10:14:42 -0600 Subject: [PATCH 091/577] USER-H5MD.cmake: make hdf5 incldir public --- cmake/Modules/Packages/USER-H5MD.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/Modules/Packages/USER-H5MD.cmake b/cmake/Modules/Packages/USER-H5MD.cmake index cf5623f46d..2893f7903c 100644 --- a/cmake/Modules/Packages/USER-H5MD.cmake +++ b/cmake/Modules/Packages/USER-H5MD.cmake @@ -3,5 +3,5 @@ if(PKG_USER-H5MD) find_package(HDF5 REQUIRED) target_link_libraries(h5md PRIVATE ${HDF5_LIBRARIES}) - target_include_directories(h5md PRIVATE ${HDF5_INCLUDE_DIRS}) + target_include_directories(h5md PUBLIC ${HDF5_INCLUDE_DIRS}) endif() -- GitLab From 2571b6058e82315fc7031b083b34fb05b9da06cc Mon Sep 17 00:00:00 2001 From: Christoph Junghans Date: Wed, 25 Mar 2020 11:26:19 -0600 Subject: [PATCH 092/577] LATTE.cmake: create and use imported target --- cmake/Modules/FindLATTE.cmake | 13 +++++++++++-- cmake/Modules/Packages/LATTE.cmake | 10 +++++----- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/cmake/Modules/FindLATTE.cmake b/cmake/Modules/FindLATTE.cmake index 74d5173bf0..ac5c639b79 100644 --- a/cmake/Modules/FindLATTE.cmake +++ b/cmake/Modules/FindLATTE.cmake @@ -7,12 +7,21 @@ find_library(LATTE_LIBRARY NAMES latte) -set(LATTE_LIBRARIES ${LATTE_LIBRARY}) - include(FindPackageHandleStandardArgs) # handle the QUIETLY and REQUIRED arguments and set LATTE_FOUND to TRUE # if all listed variables are TRUE find_package_handle_standard_args(LATTE DEFAULT_MSG LATTE_LIBRARY) +# Copy the results to the output variables and target. +if(LATTE_FOUND) + set(LATTE_LIBRARIES ${LATTE_LIBRARY}) + + if(NOT TARGET LATTE::latte) + add_library(LATTE::latte UNKNOWN IMPORTED) + set_target_properties(LATTE::latte PROPERTIES + IMPORTED_LOCATION "${LATTE_LIBRARY}") + endif() +endif() + mark_as_advanced(LATTE_LIBRARY) diff --git a/cmake/Modules/Packages/LATTE.cmake b/cmake/Modules/Packages/LATTE.cmake index abadd1cd97..20944db1a9 100644 --- a/cmake/Modules/Packages/LATTE.cmake +++ b/cmake/Modules/Packages/LATTE.cmake @@ -26,15 +26,15 @@ if(PKG_LATTE) ) add_dependencies(lammps latte_build) ExternalProject_get_property(latte_build INSTALL_DIR) - set(LATTE_LIBRARIES ${INSTALL_DIR}/${_LATTE_LIBDIR}/liblatte.a) + target_link_libraries(lammps PRIVATE ${INSTALL_DIR}/${_LATTE_LIBDIR}/liblatte.a ${LAPACK_LIBRARIES}) + if(NOT LAPACK_FOUND) + add_dependencies(latte_build linalg) + endif() else() find_package(LATTE) if(NOT LATTE_FOUND) message(FATAL_ERROR "LATTE library not found, help CMake to find it by setting LATTE_LIBRARY, or set DOWNLOAD_LATTE=ON to download it") endif() + target_link_libraries(lammps PRIVATE LATTE::latte) endif() - if(NOT LAPACK_FOUND) - add_dependencies(latte_build linalg) - endif() - target_link_libraries(lammps PRIVATE ${LATTE_LIBRARIES} ${LAPACK_LIBRARIES}) endif() -- GitLab From 299f79c91932edbb870ae8f14df5f5f1610344ff Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 25 Mar 2020 13:55:31 -0600 Subject: [PATCH 093/577] Remove deprecated Kokkos code --- src/KOKKOS/comm_kokkos.cpp | 42 +++++++++++++++--------------- src/KOKKOS/fft3d_kokkos.cpp | 8 +++--- src/KOKKOS/gridcomm_kokkos.cpp | 8 +++--- src/KOKKOS/kokkos_type.h | 2 +- src/KOKKOS/pack_kokkos.h | 16 ++++++------ src/KOKKOS/pair_kokkos.h | 18 ++++++++----- src/KOKKOS/pair_snap_kokkos_impl.h | 7 +++-- src/KOKKOS/remap_kokkos.cpp | 4 +-- 8 files changed, 57 insertions(+), 48 deletions(-) diff --git a/src/KOKKOS/comm_kokkos.cpp b/src/KOKKOS/comm_kokkos.cpp index a1ece37efd..628b0b668a 100644 --- a/src/KOKKOS/comm_kokkos.cpp +++ b/src/KOKKOS/comm_kokkos.cpp @@ -205,7 +205,7 @@ void CommKokkos::forward_comm_device(int dummy) } n = avec->pack_comm_kokkos(sendnum[iswap],k_sendlist, iswap,k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); if (n) { MPI_Send(k_buf_send.view().data(), n,MPI_DOUBLE,sendproc[iswap],0,world); @@ -224,14 +224,14 @@ void CommKokkos::forward_comm_device(int dummy) } n = avec->pack_comm_vel_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); if (n) { MPI_Send(k_buf_send.view().data(),n, MPI_DOUBLE,sendproc[iswap],0,world); } if (size_forward_recv[iswap]) MPI_Wait(&request,MPI_STATUS_IGNORE); avec->unpack_comm_vel_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_recv); - DeviceType::fence(); + DeviceType().fence(); } else { if (size_forward_recv[iswap]) MPI_Irecv(k_buf_recv.view().data(), @@ -239,26 +239,26 @@ void CommKokkos::forward_comm_device(int dummy) recvproc[iswap],0,world,&request); n = avec->pack_comm_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); if (n) MPI_Send(k_buf_send.view().data(),n, MPI_DOUBLE,sendproc[iswap],0,world); if (size_forward_recv[iswap]) MPI_Wait(&request,MPI_STATUS_IGNORE); avec->unpack_comm_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_recv); - DeviceType::fence(); + DeviceType().fence(); } } else { if (!ghost_velocity) { if (sendnum[iswap]) n = avec->pack_comm_self(sendnum[iswap],k_sendlist,iswap, firstrecv[iswap],pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); } else { n = avec->pack_comm_vel_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_send,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); avec->unpack_comm_vel_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_send); - DeviceType::fence(); + DeviceType().fence(); } } } @@ -334,7 +334,7 @@ void CommKokkos::reverse_comm_device() size_reverse_recv[iswap],MPI_DOUBLE, sendproc[iswap],0,world,&request); n = avec->pack_reverse_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_send); - DeviceType::fence(); + DeviceType().fence(); if (n) MPI_Send(k_buf_send.view().data(),n, MPI_DOUBLE,recvproc[iswap],0,world); @@ -342,7 +342,7 @@ void CommKokkos::reverse_comm_device() } avec->unpack_reverse_kokkos(sendnum[iswap],k_sendlist,iswap, k_buf_recv); - DeviceType::fence(); + DeviceType().fence(); } else { if (sendnum[iswap]) n = avec->unpack_reverse_self(sendnum[iswap],k_sendlist,iswap, @@ -410,7 +410,7 @@ void CommKokkos::forward_comm_pair_device(Pair *pair) n = pairKKBase->pack_forward_comm_kokkos(sendnum[iswap],k_sendlist, iswap,k_buf_send_pair,pbc_flag[iswap],pbc[iswap]); - DeviceType::fence(); + DeviceType().fence(); // exchange with another proc // if self, set recv buffer to send buffer @@ -445,7 +445,7 @@ void CommKokkos::forward_comm_pair_device(Pair *pair) // unpack buffer pairKKBase->unpack_forward_comm_kokkos(recvnum[iswap],firstrecv[iswap],k_buf_recv_pair); - DeviceType::fence(); + DeviceType().fence(); } } @@ -647,7 +647,7 @@ void CommKokkos::exchange_device() k_exchange_sendlist,k_exchange_copylist, ExecutionSpaceFromDevice::space, dim,lo,hi); - DeviceType::fence(); + DeviceType().fence(); } else { while (i < nlocal) { if (x[i][dim] < lo || x[i][dim] >= hi) { @@ -671,7 +671,7 @@ void CommKokkos::exchange_device() atom->nlocal=avec-> unpack_exchange_kokkos(k_buf_send,nrecv,atom->nlocal,dim,lo,hi, ExecutionSpaceFromDevice::space); - DeviceType::fence(); + DeviceType().fence(); } } else { MPI_Sendrecv(&nsend,1,MPI_INT,procneigh[dim][0],0, @@ -704,7 +704,7 @@ void CommKokkos::exchange_device() atom->nlocal = avec-> unpack_exchange_kokkos(k_buf_recv,nrecv,atom->nlocal,dim,lo,hi, ExecutionSpaceFromDevice::space); - DeviceType::fence(); + DeviceType().fence(); } } @@ -964,13 +964,13 @@ void CommKokkos::borders_device() { n = avec-> pack_border_vel_kokkos(nsend,k_sendlist,k_buf_send,iswap, pbc_flag[iswap],pbc[iswap],exec_space); - DeviceType::fence(); + DeviceType().fence(); } else { n = avec-> pack_border_kokkos(nsend,k_sendlist,k_buf_send,iswap, pbc_flag[iswap],pbc[iswap],exec_space); - DeviceType::fence(); + DeviceType().fence(); } // swap atoms with other proc @@ -1000,21 +1000,21 @@ void CommKokkos::borders_device() { if (sendproc[iswap] != me) { avec->unpack_border_vel_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_recv,exec_space); - DeviceType::fence(); + DeviceType().fence(); } else { avec->unpack_border_vel_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_send,exec_space); - DeviceType::fence(); + DeviceType().fence(); } } else { if (sendproc[iswap] != me) { avec->unpack_border_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_recv,exec_space); - DeviceType::fence(); + DeviceType().fence(); } else { avec->unpack_border_kokkos(nrecv,atom->nlocal+atom->nghost, k_buf_send,exec_space); - DeviceType::fence(); + DeviceType().fence(); } } // set all pointers & counters diff --git a/src/KOKKOS/fft3d_kokkos.cpp b/src/KOKKOS/fft3d_kokkos.cpp index 26e6e93ad9..bedd15df93 100644 --- a/src/KOKKOS/fft3d_kokkos.cpp +++ b/src/KOKKOS/fft3d_kokkos.cpp @@ -230,7 +230,7 @@ void FFT3dKokkos::fft_3d_kokkos(typename FFT_AT::t_FFT_DATA_1d d_in, cufftExec(plan->plan_fast,d_data.data(),d_data.data(),flag); #else typename FFT_AT::t_FFT_DATA_1d d_tmp = - typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.dimension_0()); + typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.extent(0)); kiss_fft_functor f; if (flag == -1) f = kiss_fft_functor(d_data,d_tmp,plan->cfg_fast_forward,length); @@ -238,7 +238,7 @@ void FFT3dKokkos::fft_3d_kokkos(typename FFT_AT::t_FFT_DATA_1d d_in, f = kiss_fft_functor(d_data,d_tmp,plan->cfg_fast_backward,length); Kokkos::parallel_for(total/length,f); d_data = d_tmp; - d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.dimension_0()); + d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.extent(0)); #endif @@ -281,7 +281,7 @@ void FFT3dKokkos::fft_3d_kokkos(typename FFT_AT::t_FFT_DATA_1d d_in, f = kiss_fft_functor(d_data,d_tmp,plan->cfg_mid_backward,length); Kokkos::parallel_for(total/length,f); d_data = d_tmp; - d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.dimension_0()); + d_tmp = typename FFT_AT::t_FFT_DATA_1d(Kokkos::view_alloc("fft_3d:tmp",Kokkos::WithoutInitializing),d_in.extent(0)); #endif // 2nd mid-remap to prepare for 3rd FFTs @@ -864,7 +864,7 @@ void FFT3dKokkos::fft_3d_1d_only_kokkos(typename FFT_AT::t_FFT_DATA_ cufftExec(plan->plan_slow,d_data.data(),d_data.data(),flag); #else kiss_fft_functor f; - typename FFT_AT::t_FFT_DATA_1d d_tmp = typename FFT_AT::t_FFT_DATA_1d("fft_3d:tmp",d_data.dimension_0()); + typename FFT_AT::t_FFT_DATA_1d d_tmp = typename FFT_AT::t_FFT_DATA_1d("fft_3d:tmp",d_data.extent(0)); if (flag == -1) { f = kiss_fft_functor(d_data,d_tmp,plan->cfg_fast_forward,length1); Kokkos::parallel_for(total1/length1,f); diff --git a/src/KOKKOS/gridcomm_kokkos.cpp b/src/KOKKOS/gridcomm_kokkos.cpp index f1ccffe20d..bdf816b647 100644 --- a/src/KOKKOS/gridcomm_kokkos.cpp +++ b/src/KOKKOS/gridcomm_kokkos.cpp @@ -524,7 +524,7 @@ void GridCommKokkos::forward_comm(KSpace *kspace, int which) kspaceKKBase->pack_forward_kspace_kokkos(which,k_buf2,swap[m].npack,k_packlist,m); else kspaceKKBase->pack_forward_kspace_kokkos(which,k_buf1,swap[m].npack,k_packlist,m); - DeviceType::fence(); + DeviceType().fence(); if (swap[m].sendproc != me) { FFT_SCALAR* buf1; @@ -552,7 +552,7 @@ void GridCommKokkos::forward_comm(KSpace *kspace, int which) } kspaceKKBase->unpack_forward_kspace_kokkos(which,k_buf2,swap[m].nunpack,k_unpacklist,m); - DeviceType::fence(); + DeviceType().fence(); } } @@ -574,7 +574,7 @@ void GridCommKokkos::reverse_comm(KSpace *kspace, int which) kspaceKKBase->pack_reverse_kspace_kokkos(which,k_buf2,swap[m].nunpack,k_unpacklist,m); else kspaceKKBase->pack_reverse_kspace_kokkos(which,k_buf1,swap[m].nunpack,k_unpacklist,m); - DeviceType::fence(); + DeviceType().fence(); if (swap[m].recvproc != me) { FFT_SCALAR* buf1; @@ -602,7 +602,7 @@ void GridCommKokkos::reverse_comm(KSpace *kspace, int which) } kspaceKKBase->unpack_reverse_kspace_kokkos(which,k_buf2,swap[m].npack,k_packlist,m); - DeviceType::fence(); + DeviceType().fence(); } } diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index d21b9eecd2..2e68cc0405 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -1012,7 +1012,7 @@ void memset_kokkos (ViewType &view) { #else Kokkos::parallel_for(view.span()*sizeof(typename ViewType::value_type)/4, f); #endif - ViewType::execution_space::fence(); + ViewType::execution_space().fence(); } struct params_lj_coul { diff --git a/src/KOKKOS/pack_kokkos.h b/src/KOKKOS/pack_kokkos.h index 62e7960999..400048b1f0 100644 --- a/src/KOKKOS/pack_kokkos.h +++ b/src/KOKKOS/pack_kokkos.h @@ -86,7 +86,7 @@ static void pack_3d(typename FFT_AT::t_FFT_SCALAR_1d_um d_data, int data_offset, const int nfast = plan->nfast; pack_3d_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -140,7 +140,7 @@ static void unpack_3d(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int buf_offset, const int nfast = plan->nfast; unpack_3d_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -195,7 +195,7 @@ static void unpack_3d_permute1_1(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute1_1_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- unpack from buf -> data, one axis permutation, 2 values/element @@ -249,7 +249,7 @@ static void unpack_3d_permute1_2(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute1_2_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -305,7 +305,7 @@ static void unpack_3d_permute1_n(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute1_n_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -358,7 +358,7 @@ static void unpack_3d_permute2_1(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute2_1_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- @@ -412,7 +412,7 @@ static void unpack_3d_permute2_2(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute2_2_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } /* ---------------------------------------------------------------------- unpack from buf -> data, two axis permutation, nqty values/element @@ -466,7 +466,7 @@ static void unpack_3d_permute2_n(typename FFT_AT::t_FFT_SCALAR_1d_um d_buf, int const int nfast = plan->nfast; unpack_3d_permute2_n_functor f(d_buf,buf_offset,d_data,data_offset,plan); Kokkos::parallel_for(nslow*nmid*nfast,f); - DeviceType::fence(); + DeviceType().fence(); } }; diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index 52a05b3991..d501324960 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -444,7 +444,7 @@ struct PairComputeFunctor { ev.evdwl += fev.evdwl; if (c.eflag_atom) - d_eatom(i,0) += fev.evdwl; + d_eatom(i) += fev.evdwl; if (c.vflag_global) { ev.v[0] += fev.v[0]; @@ -554,7 +554,7 @@ struct PairComputeFunctor { } if (c.eflag_atom) - d_eatom(i,0) += fev.evdwl + fev.ecoul; + d_eatom(i) += fev.evdwl + fev.ecoul; if (c.vflag_global) { ev.v[0] += fev.v[0]; @@ -850,8 +850,14 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable } template -int GetTeamSize(FunctorStyle& functor, int team_size, int vector_length) { - int team_size_max = Kokkos::TeamPolicy<>::team_size_max(functor); +int GetTeamSize(FunctorStyle& functor, int inum, int reduce_flag, int team_size, int vector_length) { + int team_size_max; + if (reduce_flag) { + EV_FLOAT ev; + team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,ev,Kokkos::ParallelReduceTag()); + } else { + team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,Kokkos::ParallelForTag()); + } #ifdef KOKKOS_ENABLE_CUDA if(team_size*vector_length > team_size_max) @@ -877,13 +883,13 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable if(fpair->atom->ntypes > MAX_TYPES_STACKPARAMS) { PairComputeFunctor ff(fpair,list); - atoms_per_team = GetTeamSize(ff, atoms_per_team, vector_length); + atoms_per_team = GetTeamSize(ff, list->inum, (fpair->eflag || fpair->vflag), atoms_per_team, vector_length); Kokkos::TeamPolicy > policy(list->inum,atoms_per_team,vector_length); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(policy,ff,ev); else Kokkos::parallel_for(policy,ff); } else { PairComputeFunctor ff(fpair,list); - atoms_per_team = GetTeamSize(ff, atoms_per_team, vector_length); + atoms_per_team = GetTeamSize(ff, list->inum, (fpair->eflag || fpair->vflag), atoms_per_team, vector_length); Kokkos::TeamPolicy > policy(list->inum,atoms_per_team,vector_length); if (fpair->eflag || fpair->vflag) Kokkos::parallel_reduce(policy,ff,ev); else Kokkos::parallel_for(policy,ff); diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index d807f149a9..d4e5535614 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -182,11 +182,14 @@ void PairSNAPKokkos::compute(int eflag_in, int vflag_in) if (max_neighs(k_list), Kokkos::Experimental::Max(max_neighs)); + Kokkos::parallel_reduce("PairSNAPKokkos::find_max_neighs",inum, FindMaxNumNeighs(k_list), Kokkos::Max(max_neighs)); + + int chunk_size = MIN(2000,inum); + chunk_offset = 0; int vector_length = 1; int team_size = 1; - int team_size_max = Kokkos::TeamPolicy::team_size_max(*this); + int team_size_max = Kokkos::TeamPolicy(chunk_size,Kokkos::AUTO).team_size_max(*this,Kokkos::ParallelForTag()); #ifdef KOKKOS_ENABLE_CUDA team_size = 32;//max_neighs; if (team_size*vector_length > team_size_max) diff --git a/src/KOKKOS/remap_kokkos.cpp b/src/KOKKOS/remap_kokkos.cpp index c809aa034c..0d1ce46d7d 100644 --- a/src/KOKKOS/remap_kokkos.cpp +++ b/src/KOKKOS/remap_kokkos.cpp @@ -120,7 +120,7 @@ void RemapKokkos::remap_3d_kokkos(typename FFT_AT::t_FFT_SCALAR_1d d // post all recvs into scratch space for (irecv = 0; irecv < plan->nrecv; irecv++) { - FFT_SCALAR* scratch = d_scratch.ptr_on_device() + plan->recv_bufloc[irecv]; + FFT_SCALAR* scratch = d_scratch.data() + plan->recv_bufloc[irecv]; MPI_Irecv(scratch,plan->recv_size[irecv], MPI_FFT_SCALAR,plan->recv_proc[irecv],0, plan->comm,&plan->request[irecv]); @@ -132,7 +132,7 @@ void RemapKokkos::remap_3d_kokkos(typename FFT_AT::t_FFT_SCALAR_1d d int in_offset = plan->send_offset[isend]; plan->pack(d_in,in_offset, plan->d_sendbuf,0,&plan->packplan[isend]); - MPI_Send(plan->d_sendbuf.ptr_on_device(),plan->send_size[isend],MPI_FFT_SCALAR, + MPI_Send(plan->d_sendbuf.data(),plan->send_size[isend],MPI_FFT_SCALAR, plan->send_proc[isend],0,plan->comm); } -- GitLab From 7a09636f9a80c486aa7f7afbc55c78d28664ce03 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 5 Feb 2020 14:36:39 -0700 Subject: [PATCH 094/577] Fix compile issue in pair_kokkos.h --- src/KOKKOS/pair_kokkos.h | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index d501324960..c9f375de4b 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -852,12 +852,11 @@ EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable template int GetTeamSize(FunctorStyle& functor, int inum, int reduce_flag, int team_size, int vector_length) { int team_size_max; - if (reduce_flag) { - EV_FLOAT ev; - team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,ev,Kokkos::ParallelReduceTag()); - } else { + + if (reduce_flag) + team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,Kokkos::ParallelReduceTag()); + else team_size_max = Kokkos::TeamPolicy<>(inum,Kokkos::AUTO).team_size_max(functor,Kokkos::ParallelForTag()); - } #ifdef KOKKOS_ENABLE_CUDA if(team_size*vector_length > team_size_max) -- GitLab From 4eebcdfc0db5b6afbf6fa9a7dffb5f6ebd0e11d3 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 5 Feb 2020 16:35:43 -0700 Subject: [PATCH 095/577] Fix runtime issue in Kokkos --- src/KOKKOS/atom_vec_angle_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_atomic_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_bond_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_charge_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_dpd_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_full_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_molecular_kokkos.cpp | 6 +++--- src/KOKKOS/atom_vec_sphere_kokkos.cpp | 6 +++--- 8 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/KOKKOS/atom_vec_angle_kokkos.cpp b/src/KOKKOS/atom_vec_angle_kokkos.cpp index 736e1c1fca..5b934e2434 100644 --- a/src/KOKKOS/atom_vec_angle_kokkos.cpp +++ b/src/KOKKOS/atom_vec_angle_kokkos.cpp @@ -74,9 +74,9 @@ void AtomVecAngleKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); memoryKK->grow_kokkos(atomKK->k_nspecial,atomKK->nspecial,nmax,3,"atom:nspecial"); diff --git a/src/KOKKOS/atom_vec_atomic_kokkos.cpp b/src/KOKKOS/atom_vec_atomic_kokkos.cpp index 4fec5740d6..df30b50dd0 100644 --- a/src/KOKKOS/atom_vec_atomic_kokkos.cpp +++ b/src/KOKKOS/atom_vec_atomic_kokkos.cpp @@ -70,9 +70,9 @@ void AtomVecAtomicKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); grow_reset(); atomKK->sync(Host,ALL_MASK); diff --git a/src/KOKKOS/atom_vec_bond_kokkos.cpp b/src/KOKKOS/atom_vec_bond_kokkos.cpp index 4475131d77..b614d94bce 100644 --- a/src/KOKKOS/atom_vec_bond_kokkos.cpp +++ b/src/KOKKOS/atom_vec_bond_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecBondKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); memoryKK->grow_kokkos(atomKK->k_nspecial,atomKK->nspecial,nmax,3,"atom:nspecial"); diff --git a/src/KOKKOS/atom_vec_charge_kokkos.cpp b/src/KOKKOS/atom_vec_charge_kokkos.cpp index 3f26b1e9ea..a9cee3aca8 100644 --- a/src/KOKKOS/atom_vec_charge_kokkos.cpp +++ b/src/KOKKOS/atom_vec_charge_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecChargeKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_q,atomKK->q,nmax,"atom:q"); diff --git a/src/KOKKOS/atom_vec_dpd_kokkos.cpp b/src/KOKKOS/atom_vec_dpd_kokkos.cpp index 144ef26f19..dfc122b1ef 100644 --- a/src/KOKKOS/atom_vec_dpd_kokkos.cpp +++ b/src/KOKKOS/atom_vec_dpd_kokkos.cpp @@ -75,9 +75,9 @@ void AtomVecDPDKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_rho,atomKK->rho,nmax,"atom:rho"); diff --git a/src/KOKKOS/atom_vec_full_kokkos.cpp b/src/KOKKOS/atom_vec_full_kokkos.cpp index 1fdbcbec8c..b5239867fb 100644 --- a/src/KOKKOS/atom_vec_full_kokkos.cpp +++ b/src/KOKKOS/atom_vec_full_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecFullKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_q,atomKK->q,nmax,"atom:q"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); diff --git a/src/KOKKOS/atom_vec_molecular_kokkos.cpp b/src/KOKKOS/atom_vec_molecular_kokkos.cpp index f3b4ae98ca..fec0183971 100644 --- a/src/KOKKOS/atom_vec_molecular_kokkos.cpp +++ b/src/KOKKOS/atom_vec_molecular_kokkos.cpp @@ -73,9 +73,9 @@ void AtomVecMolecularKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_molecule,atomKK->molecule,nmax,"atom:molecule"); memoryKK->grow_kokkos(atomKK->k_nspecial,atomKK->nspecial,nmax,3,"atom:nspecial"); diff --git a/src/KOKKOS/atom_vec_sphere_kokkos.cpp b/src/KOKKOS/atom_vec_sphere_kokkos.cpp index 67aaa32c21..31f8180b4c 100644 --- a/src/KOKKOS/atom_vec_sphere_kokkos.cpp +++ b/src/KOKKOS/atom_vec_sphere_kokkos.cpp @@ -107,9 +107,9 @@ void AtomVecSphereKokkos::grow(int n) memoryKK->grow_kokkos(atomKK->k_mask,atomKK->mask,nmax,"atom:mask"); memoryKK->grow_kokkos(atomKK->k_image,atomKK->image,nmax,"atom:image"); - memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,3,"atom:x"); - memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,3,"atom:v"); - memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,3,"atom:f"); + memoryKK->grow_kokkos(atomKK->k_x,atomKK->x,nmax,"atom:x"); + memoryKK->grow_kokkos(atomKK->k_v,atomKK->v,nmax,"atom:v"); + memoryKK->grow_kokkos(atomKK->k_f,atomKK->f,nmax,"atom:f"); memoryKK->grow_kokkos(atomKK->k_radius,atomKK->radius,nmax,"atom:radius"); memoryKK->grow_kokkos(atomKK->k_rmass,atomKK->rmass,nmax,"atom:rmass"); memoryKK->grow_kokkos(atomKK->k_omega,atomKK->omega,nmax,3,"atom:omega"); -- GitLab From 1e7e9369dab0d5310d80e7c26458fa9fa78911e6 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 6 Feb 2020 08:44:58 -0700 Subject: [PATCH 096/577] Fix runtime error in Kokkos package --- src/KOKKOS/kokkos_type.h | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index 2e68cc0405..3ba6318d41 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -980,17 +980,9 @@ typedef struct ArrayTypes HAT; template void buffer_view(BufferView &buf, DualView &view, const size_t n0, - const size_t n1 = 0, - const size_t n2 = 0, - const size_t n3 = 0, - const size_t n4 = 0, - const size_t n5 = 0, - const size_t n6 = 0, - const size_t n7 = 0) { - - buf = BufferView( - view.template view().data(), - n0,n1,n2,n3,n4,n5,n6,n7); + const size_t n1) { + + buf = BufferView(view.template view().data(),n0,n1); } -- GitLab From 0025dfe1e3fd79bb557048143ccb48296549337c Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Thu, 6 Feb 2020 09:35:04 -0700 Subject: [PATCH 097/577] Update Kokkos CUDA minimum verison --- doc/src/Speed_kokkos.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/src/Speed_kokkos.rst b/doc/src/Speed_kokkos.rst index 6658957006..ab8444b845 100644 --- a/doc/src/Speed_kokkos.rst +++ b/doc/src/Speed_kokkos.rst @@ -38,7 +38,7 @@ compatible with specific hardware. .. note:: To build with Kokkos support for NVIDIA GPUs, NVIDIA CUDA - software version 7.5 or later must be installed on your system. See + software version 9.0 or later must be installed on your system. See the discussion for the :doc:`GPU package ` for details of how to check and do this. -- GitLab From e298978da0f758b44644d82859cd701ae7923469 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 25 Mar 2020 13:58:12 -0600 Subject: [PATCH 098/577] Change Kokkos::Impl to std namespace --- src/KOKKOS/atom_kokkos.h | 16 ++++++++-------- src/KOKKOS/fix_qeq_reax_kokkos.cpp | 6 +++--- src/KOKKOS/fix_rx_kokkos.cpp | 6 +++--- src/KOKKOS/fix_shardlow_kokkos.cpp | 6 +++--- src/KOKKOS/pair_buck_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_buck_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_buck_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_debye_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_dsf_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_coul_wolf_kokkos.cpp | 6 +++--- src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp | 12 ++++++------ src/KOKKOS/pair_eam_alloy_kokkos.cpp | 6 +++--- src/KOKKOS/pair_eam_fs_kokkos.cpp | 6 +++--- src/KOKKOS/pair_eam_kokkos.cpp | 6 +++--- src/KOKKOS/pair_exp6_rx_kokkos.cpp | 6 +++--- src/KOKKOS/pair_gran_hooke_history_kokkos.cpp | 6 +++--- src/KOKKOS/pair_kokkos.h | 4 ++-- ...air_lj_charmm_coul_charmm_implicit_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_class2_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_cut_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_expand_kokkos.cpp | 6 +++--- .../pair_lj_gromacs_coul_gromacs_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_gromacs_kokkos.cpp | 6 +++--- src/KOKKOS/pair_lj_sdk_kokkos.cpp | 6 +++--- src/KOKKOS/pair_morse_kokkos.cpp | 6 +++--- src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp | 6 +++--- src/KOKKOS/pair_reaxc_kokkos.cpp | 6 +++--- src/KOKKOS/pair_snap_kokkos_impl.h | 6 +++--- src/KOKKOS/pair_sw_kokkos.cpp | 6 +++--- src/KOKKOS/pair_table_kokkos.cpp | 6 +++--- src/KOKKOS/pair_table_rx_kokkos.cpp | 6 +++--- src/KOKKOS/pair_tersoff_kokkos.cpp | 6 +++--- src/KOKKOS/pair_tersoff_mod_kokkos.cpp | 6 +++--- src/KOKKOS/pair_tersoff_zbl_kokkos.cpp | 6 +++--- src/KOKKOS/pair_vashishta_kokkos.cpp | 6 +++--- src/KOKKOS/pair_yukawa_kokkos.cpp | 6 +++--- src/KOKKOS/pair_zbl_kokkos.cpp | 6 +++--- src/KOKKOS/sna_kokkos_impl.h | 2 +- 48 files changed, 149 insertions(+), 149 deletions(-) diff --git a/src/KOKKOS/atom_kokkos.h b/src/KOKKOS/atom_kokkos.h index a83b299ebd..0ae032032a 100644 --- a/src/KOKKOS/atom_kokkos.h +++ b/src/KOKKOS/atom_kokkos.h @@ -83,32 +83,32 @@ class SortFunctor { ViewType source; Kokkos::View dest; IndexView index; - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0)); } - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0),src.extent(1)); } - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0),src.extent(1),src.extent(2)); } - SortFunctor(ViewType src, typename Kokkos::Impl::enable_if::type ind):source(src),index(ind){ + SortFunctor(ViewType src, typename std::enable_if::type ind):source(src),index(ind){ dest = Kokkos::View("",src.extent(0),src.extent(1),src.extent(2),src.extent(3)); } KOKKOS_INLINE_FUNCTION - void operator()(const typename Kokkos::Impl::enable_if::type& i) { + void operator()(const typename std::enable_if::type& i) { dest(i) = source(index(i)); } - void operator()(const typename Kokkos::Impl::enable_if::type& i) { + void operator()(const typename std::enable_if::type& i) { for(int j=0;j::type& i) { + void operator()(const typename std::enable_if::type& i) { for(int j=0;j::type& i) { + void operator()(const typename std::enable_if::type& i) { for(int j=0;j::init() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->fix = 1; diff --git a/src/KOKKOS/fix_rx_kokkos.cpp b/src/KOKKOS/fix_rx_kokkos.cpp index e06fc14585..dcb1ac0b71 100644 --- a/src/KOKKOS/fix_rx_kokkos.cpp +++ b/src/KOKKOS/fix_rx_kokkos.cpp @@ -146,10 +146,10 @@ void FixRxKokkos::init() int neighflag = lmp->kokkos->neighflag; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/fix_shardlow_kokkos.cpp b/src/KOKKOS/fix_shardlow_kokkos.cpp index 9bd8594341..c6ad47501a 100644 --- a/src/KOKKOS/fix_shardlow_kokkos.cpp +++ b/src/KOKKOS/fix_shardlow_kokkos.cpp @@ -132,10 +132,10 @@ void FixShardlowKokkos::init() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; // neighbor->requests[irequest]->pair = 0; // neighbor->requests[irequest]->fix = 1; diff --git a/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp b/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp index 2a72617525..97154f7604 100644 --- a/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_buck_coul_cut_kokkos.cpp @@ -296,10 +296,10 @@ void PairBuckCoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_buck_coul_long_kokkos.cpp b/src/KOKKOS/pair_buck_coul_long_kokkos.cpp index fdf395684a..a55c6b25f6 100644 --- a/src/KOKKOS/pair_buck_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_buck_coul_long_kokkos.cpp @@ -456,10 +456,10 @@ void PairBuckCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_buck_kokkos.cpp b/src/KOKKOS/pair_buck_kokkos.cpp index 375d0dc1ea..76ff246be4 100644 --- a/src/KOKKOS/pair_buck_kokkos.cpp +++ b/src/KOKKOS/pair_buck_kokkos.cpp @@ -218,10 +218,10 @@ void PairBuckKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_cut_kokkos.cpp b/src/KOKKOS/pair_coul_cut_kokkos.cpp index 5a1a6eefac..210144040c 100644 --- a/src/KOKKOS/pair_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_coul_cut_kokkos.cpp @@ -220,10 +220,10 @@ void PairCoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_debye_kokkos.cpp b/src/KOKKOS/pair_coul_debye_kokkos.cpp index 8dd7e4f3d2..46a7df7cb1 100644 --- a/src/KOKKOS/pair_coul_debye_kokkos.cpp +++ b/src/KOKKOS/pair_coul_debye_kokkos.cpp @@ -265,10 +265,10 @@ void PairCoulDebyeKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_dsf_kokkos.cpp b/src/KOKKOS/pair_coul_dsf_kokkos.cpp index 836b12ba39..f7bf8fb5d1 100644 --- a/src/KOKKOS/pair_coul_dsf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_dsf_kokkos.cpp @@ -202,10 +202,10 @@ void PairCoulDSFKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_long_kokkos.cpp b/src/KOKKOS/pair_coul_long_kokkos.cpp index 84b89c6373..19a40dad0b 100644 --- a/src/KOKKOS/pair_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_coul_long_kokkos.cpp @@ -416,10 +416,10 @@ void PairCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_coul_wolf_kokkos.cpp b/src/KOKKOS/pair_coul_wolf_kokkos.cpp index 3ca8f16a79..f3ffdc6069 100644 --- a/src/KOKKOS/pair_coul_wolf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_wolf_kokkos.cpp @@ -203,10 +203,10 @@ void PairCoulWolfKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp index 21fd32a2c8..1ddf950fd7 100644 --- a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp +++ b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp @@ -87,10 +87,10 @@ void PairDPDfdtEnergyKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; @@ -125,10 +125,10 @@ void PairDPDfdtEnergyKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_eam_alloy_kokkos.cpp b/src/KOKKOS/pair_eam_alloy_kokkos.cpp index 48bf63386a..87bb5dddf2 100644 --- a/src/KOKKOS/pair_eam_alloy_kokkos.cpp +++ b/src/KOKKOS/pair_eam_alloy_kokkos.cpp @@ -302,10 +302,10 @@ void PairEAMAlloyKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_eam_fs_kokkos.cpp b/src/KOKKOS/pair_eam_fs_kokkos.cpp index 6536dd745a..37fab42d4b 100644 --- a/src/KOKKOS/pair_eam_fs_kokkos.cpp +++ b/src/KOKKOS/pair_eam_fs_kokkos.cpp @@ -302,10 +302,10 @@ void PairEAMFSKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_eam_kokkos.cpp b/src/KOKKOS/pair_eam_kokkos.cpp index 3358fe709c..06e26301a4 100644 --- a/src/KOKKOS/pair_eam_kokkos.cpp +++ b/src/KOKKOS/pair_eam_kokkos.cpp @@ -296,10 +296,10 @@ void PairEAMKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index f3f63c98b2..4d72c85029 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -118,10 +118,10 @@ void PairExp6rxKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp index 5071bae32f..9e65c0589e 100644 --- a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp +++ b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp @@ -86,10 +86,10 @@ void PairGranHookeHistoryKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == HALF || neighflag == HALFTHREAD) { neighbor->requests[irequest]->full = 0; diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index c9f375de4b..41922b7349 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -841,7 +841,7 @@ struct PairComputeFunctor { // pair_compute_neighlist will match - either the dummy version // or the real one further below. template -EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable_if*>::type list) { +EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if*>::type list) { EV_FLOAT ev; (void) fpair; (void) list; @@ -869,7 +869,7 @@ int GetTeamSize(FunctorStyle& functor, int inum, int reduce_flag, int team_size, // Submit ParallelFor for NEIGHFLAG=HALF,HALFTHREAD,FULL,N2 template -EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename Kokkos::Impl::enable_if<(NEIGHFLAG&PairStyle::EnabledNeighFlags) != 0, NeighListKokkos*>::type list) { +EV_FLOAT pair_compute_neighlist (PairStyle* fpair, typename std::enable_if<(NEIGHFLAG&PairStyle::EnabledNeighFlags) != 0, NeighListKokkos*>::type list) { EV_FLOAT ev; if (!fpair->lmp->kokkos->neigh_thread_set) diff --git a/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp b/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp index ae6cb61b60..86786be6f2 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmm_coul_charmm_implicit_kokkos.cpp @@ -462,10 +462,10 @@ void PairLJCharmmCoulCharmmImplicitKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp b/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp index 9cdef267e2..3bc7cf5425 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmm_coul_charmm_kokkos.cpp @@ -464,10 +464,10 @@ void PairLJCharmmCoulCharmmKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp index 441070248d..4285d16bed 100644 --- a/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_charmm_coul_long_kokkos.cpp @@ -471,10 +471,10 @@ void PairLJCharmmCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp b/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp index 1f7642e965..f338575ff6 100644 --- a/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_lj_class2_coul_cut_kokkos.cpp @@ -298,10 +298,10 @@ void PairLJClass2CoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp index c88ff9378e..3e62b57fdc 100644 --- a/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_class2_coul_long_kokkos.cpp @@ -453,10 +453,10 @@ void PairLJClass2CoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_class2_kokkos.cpp b/src/KOKKOS/pair_lj_class2_kokkos.cpp index 9900e7361f..76406c4410 100644 --- a/src/KOKKOS/pair_lj_class2_kokkos.cpp +++ b/src/KOKKOS/pair_lj_class2_kokkos.cpp @@ -236,10 +236,10 @@ void PairLJClass2Kokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp index 1601e4a4b2..094c25471c 100644 --- a/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_cut_kokkos.cpp @@ -289,10 +289,10 @@ void PairLJCutCoulCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp index 6e7d1eeb8b..8d1f650061 100644 --- a/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_debye_kokkos.cpp @@ -318,10 +318,10 @@ void PairLJCutCoulDebyeKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp index b7dc7cc26d..bd1754df9a 100644 --- a/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_dsf_kokkos.cpp @@ -311,10 +311,10 @@ void PairLJCutCoulDSFKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp b/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp index 122d59af82..fa53850b07 100644 --- a/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_coul_long_kokkos.cpp @@ -452,10 +452,10 @@ void PairLJCutCoulLongKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_cut_kokkos.cpp b/src/KOKKOS/pair_lj_cut_kokkos.cpp index df750b7524..3770e8f816 100644 --- a/src/KOKKOS/pair_lj_cut_kokkos.cpp +++ b/src/KOKKOS/pair_lj_cut_kokkos.cpp @@ -230,10 +230,10 @@ void PairLJCutKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_expand_kokkos.cpp b/src/KOKKOS/pair_lj_expand_kokkos.cpp index 38bebc364f..c46e0d47e4 100644 --- a/src/KOKKOS/pair_lj_expand_kokkos.cpp +++ b/src/KOKKOS/pair_lj_expand_kokkos.cpp @@ -238,10 +238,10 @@ void PairLJExpandKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp b/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp index a46a5c0441..1bef3f0a27 100644 --- a/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp +++ b/src/KOKKOS/pair_lj_gromacs_coul_gromacs_kokkos.cpp @@ -447,10 +447,10 @@ void PairLJGromacsCoulGromacsKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_gromacs_kokkos.cpp b/src/KOKKOS/pair_lj_gromacs_kokkos.cpp index 23ed5e5595..cfc65c883b 100644 --- a/src/KOKKOS/pair_lj_gromacs_kokkos.cpp +++ b/src/KOKKOS/pair_lj_gromacs_kokkos.cpp @@ -285,10 +285,10 @@ void PairLJGromacsKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_lj_sdk_kokkos.cpp b/src/KOKKOS/pair_lj_sdk_kokkos.cpp index 25f081d255..cb99de3cd9 100644 --- a/src/KOKKOS/pair_lj_sdk_kokkos.cpp +++ b/src/KOKKOS/pair_lj_sdk_kokkos.cpp @@ -268,10 +268,10 @@ void PairLJSDKKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_morse_kokkos.cpp b/src/KOKKOS/pair_morse_kokkos.cpp index d3e3042a34..799278bf9e 100644 --- a/src/KOKKOS/pair_morse_kokkos.cpp +++ b/src/KOKKOS/pair_morse_kokkos.cpp @@ -247,10 +247,10 @@ void PairMorseKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp index 75247859ed..3b7a738026 100644 --- a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp +++ b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp @@ -99,10 +99,10 @@ void PairMultiLucyRXKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_reaxc_kokkos.cpp b/src/KOKKOS/pair_reaxc_kokkos.cpp index d0ad1f1b09..18144bb653 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.cpp +++ b/src/KOKKOS/pair_reaxc_kokkos.cpp @@ -147,10 +147,10 @@ void PairReaxCKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_snap_kokkos_impl.h b/src/KOKKOS/pair_snap_kokkos_impl.h index d4e5535614..ad850981cc 100644 --- a/src/KOKKOS/pair_snap_kokkos_impl.h +++ b/src/KOKKOS/pair_snap_kokkos_impl.h @@ -91,10 +91,10 @@ void PairSNAPKokkos::init_style() int irequest = neighbor->request(this,instance_me); neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == HALF || neighflag == HALFTHREAD) { // still need atomics, even though using a full neigh list neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_sw_kokkos.cpp b/src/KOKKOS/pair_sw_kokkos.cpp index e85afa362f..3ce99fe629 100644 --- a/src/KOKKOS/pair_sw_kokkos.cpp +++ b/src/KOKKOS/pair_sw_kokkos.cpp @@ -610,10 +610,10 @@ void PairSWKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; // always request a full neighbor list diff --git a/src/KOKKOS/pair_table_kokkos.cpp b/src/KOKKOS/pair_table_kokkos.cpp index 5ee24ad479..7311e4ec05 100644 --- a/src/KOKKOS/pair_table_kokkos.cpp +++ b/src/KOKKOS/pair_table_kokkos.cpp @@ -514,10 +514,10 @@ void PairTableKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_table_rx_kokkos.cpp b/src/KOKKOS/pair_table_rx_kokkos.cpp index daebeda8db..cd7aa373ed 100644 --- a/src/KOKKOS/pair_table_rx_kokkos.cpp +++ b/src/KOKKOS/pair_table_rx_kokkos.cpp @@ -1268,10 +1268,10 @@ void PairTableRXKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_tersoff_kokkos.cpp b/src/KOKKOS/pair_tersoff_kokkos.cpp index b360b20ef3..d068ac0412 100644 --- a/src/KOKKOS/pair_tersoff_kokkos.cpp +++ b/src/KOKKOS/pair_tersoff_kokkos.cpp @@ -88,10 +88,10 @@ void PairTersoffKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) error->all(FLERR,"Cannot (yet) use full neighbor list style with tersoff/kk"); diff --git a/src/KOKKOS/pair_tersoff_mod_kokkos.cpp b/src/KOKKOS/pair_tersoff_mod_kokkos.cpp index 81ef486999..5eb23d498a 100644 --- a/src/KOKKOS/pair_tersoff_mod_kokkos.cpp +++ b/src/KOKKOS/pair_tersoff_mod_kokkos.cpp @@ -88,10 +88,10 @@ void PairTersoffMODKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) error->all(FLERR,"Cannot (yet) use full neighbor list style with tersoff/mod/kk"); diff --git a/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp b/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp index 4593f32e36..2648689fad 100644 --- a/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp +++ b/src/KOKKOS/pair_tersoff_zbl_kokkos.cpp @@ -101,10 +101,10 @@ void PairTersoffZBLKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) error->all(FLERR,"Cannot (yet) use full neighbor list style with tersoff/zbl/kk"); diff --git a/src/KOKKOS/pair_vashishta_kokkos.cpp b/src/KOKKOS/pair_vashishta_kokkos.cpp index 614d3334d5..ddb0688e03 100644 --- a/src/KOKKOS/pair_vashishta_kokkos.cpp +++ b/src/KOKKOS/pair_vashishta_kokkos.cpp @@ -585,10 +585,10 @@ void PairVashishtaKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; // always request a full neighbor list diff --git a/src/KOKKOS/pair_yukawa_kokkos.cpp b/src/KOKKOS/pair_yukawa_kokkos.cpp index 6dfffd4a54..a1838c9ef6 100644 --- a/src/KOKKOS/pair_yukawa_kokkos.cpp +++ b/src/KOKKOS/pair_yukawa_kokkos.cpp @@ -120,10 +120,10 @@ void PairYukawaKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/pair_zbl_kokkos.cpp b/src/KOKKOS/pair_zbl_kokkos.cpp index 5697dd5b00..7a476e4a14 100644 --- a/src/KOKKOS/pair_zbl_kokkos.cpp +++ b/src/KOKKOS/pair_zbl_kokkos.cpp @@ -92,10 +92,10 @@ void PairZBLKokkos::init_style() int irequest = neighbor->nrequest - 1; neighbor->requests[irequest]-> - kokkos_host = Kokkos::Impl::is_same::value && - !Kokkos::Impl::is_same::value; + kokkos_host = std::is_same::value && + !std::is_same::value; neighbor->requests[irequest]-> - kokkos_device = Kokkos::Impl::is_same::value; + kokkos_device = std::is_same::value; if (neighflag == FULL) { neighbor->requests[irequest]->full = 1; diff --git a/src/KOKKOS/sna_kokkos_impl.h b/src/KOKKOS/sna_kokkos_impl.h index dcedf333e5..c6c8bbb421 100644 --- a/src/KOKKOS/sna_kokkos_impl.h +++ b/src/KOKKOS/sna_kokkos_impl.h @@ -1643,7 +1643,7 @@ double SNAKokkos::memory_usage() } #endif bytes += natom * idxu_max * sizeof(double) * 2; // ulisttot - if (!Kokkos::Impl::is_same::value) + if (!std::is_same::value) bytes += natom * idxu_max * sizeof(double) * 2; // ulisttot_lr bytes += natom * idxz_max * sizeof(double) * 2; // zlist -- GitLab From 0252d8c21073512b6dd8b85d8c21cef8eeabd175 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 11 Mar 2020 12:17:53 -0600 Subject: [PATCH 099/577] Fix compile for UVM --- src/KOKKOS/angle_charmm_kokkos.h | 6 +-- src/KOKKOS/angle_class2_kokkos.cpp | 6 +-- src/KOKKOS/angle_cosine_kokkos.cpp | 6 +-- src/KOKKOS/angle_harmonic_kokkos.cpp | 6 +-- src/KOKKOS/bond_class2_kokkos.h | 6 +-- src/KOKKOS/bond_fene_kokkos.cpp | 6 +-- src/KOKKOS/bond_harmonic_kokkos.h | 6 +-- src/KOKKOS/dihedral_charmm_kokkos.cpp | 2 +- src/KOKKOS/dihedral_charmm_kokkos.h | 8 ++-- src/KOKKOS/dihedral_class2_kokkos.cpp | 6 +-- src/KOKKOS/dihedral_harmonic_kokkos.cpp | 6 +-- src/KOKKOS/dihedral_opls_kokkos.cpp | 6 +-- src/KOKKOS/fix_qeq_reax_kokkos.h | 4 +- src/KOKKOS/fix_rx_kokkos.cpp | 6 +-- src/KOKKOS/improper_class2_kokkos.cpp | 8 ++-- src/KOKKOS/improper_class2_kokkos.h | 2 +- src/KOKKOS/improper_harmonic_kokkos.h | 6 +-- src/KOKKOS/kokkos_type.h | 14 +++++++ src/KOKKOS/pair_coul_dsf_kokkos.cpp | 8 ++-- src/KOKKOS/pair_coul_wolf_kokkos.cpp | 8 ++-- src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp | 12 +++--- src/KOKKOS/pair_eam_alloy_kokkos.h | 16 ++++---- src/KOKKOS/pair_eam_fs_kokkos.h | 16 ++++---- src/KOKKOS/pair_eam_kokkos.h | 16 ++++---- src/KOKKOS/pair_exp6_rx_kokkos.cpp | 16 ++++---- src/KOKKOS/pair_gran_hooke_history_kokkos.cpp | 6 +-- src/KOKKOS/pair_kokkos.h | 12 +++--- src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp | 8 ++-- src/KOKKOS/pair_reaxc_kokkos.cpp | 10 ++--- src/KOKKOS/pair_reaxc_kokkos.h | 38 +++++++++---------- src/KOKKOS/pair_snap_kokkos.h | 8 ++-- src/KOKKOS/pair_sw_kokkos.h | 12 +++--- src/KOKKOS/pair_table_rx_kokkos.cpp | 26 +++++++------ src/KOKKOS/pair_tersoff_kokkos.h | 12 +++--- src/KOKKOS/pair_tersoff_mod_kokkos.h | 12 +++--- src/KOKKOS/pair_tersoff_zbl_kokkos.h | 12 +++--- src/KOKKOS/pair_vashishta_kokkos.cpp | 10 ++--- src/KOKKOS/pppm_kokkos.cpp | 2 +- src/KOKKOS/sna_kokkos.h | 4 +- 39 files changed, 195 insertions(+), 179 deletions(-) diff --git a/src/KOKKOS/angle_charmm_kokkos.h b/src/KOKKOS/angle_charmm_kokkos.h index e168160562..865439b83a 100644 --- a/src/KOKKOS/angle_charmm_kokkos.h +++ b/src/KOKKOS/angle_charmm_kokkos.h @@ -63,13 +63,13 @@ class AngleCharmmKokkos : public AngleCharmm { typedef ArrayTypes AT; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d anglelist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/angle_class2_kokkos.cpp b/src/KOKKOS/angle_class2_kokkos.cpp index 809ce7e7dd..57563b959f 100644 --- a/src/KOKKOS/angle_class2_kokkos.cpp +++ b/src/KOKKOS/angle_class2_kokkos.cpp @@ -158,7 +158,7 @@ KOKKOS_INLINE_FUNCTION void AngleClass2Kokkos::operator()(TagAngleClass2Compute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = anglelist(n,0); const int i2 = anglelist(n,1); @@ -495,8 +495,8 @@ void AngleClass2Kokkos::ev_tally(EV_FLOAT &ev, const int i, const in F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.template view(); - Kokkos::View > v_vatom = k_vatom.template view(); + 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) { diff --git a/src/KOKKOS/angle_cosine_kokkos.cpp b/src/KOKKOS/angle_cosine_kokkos.cpp index da0ff398f1..65c4c1475a 100644 --- a/src/KOKKOS/angle_cosine_kokkos.cpp +++ b/src/KOKKOS/angle_cosine_kokkos.cpp @@ -141,7 +141,7 @@ KOKKOS_INLINE_FUNCTION void AngleCosineKokkos::operator()(TagAngleCosineCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = anglelist(n,0); const int i2 = anglelist(n,1); @@ -284,8 +284,8 @@ void AngleCosineKokkos::ev_tally(EV_FLOAT &ev, const int i, const in F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.template view(); - Kokkos::View > v_vatom = k_vatom.template view(); + 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) { diff --git a/src/KOKKOS/angle_harmonic_kokkos.cpp b/src/KOKKOS/angle_harmonic_kokkos.cpp index fc274bb894..4b8a87ece7 100644 --- a/src/KOKKOS/angle_harmonic_kokkos.cpp +++ b/src/KOKKOS/angle_harmonic_kokkos.cpp @@ -142,7 +142,7 @@ KOKKOS_INLINE_FUNCTION void AngleHarmonicKokkos::operator()(TagAngleHarmonicCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = anglelist(n,0); const int i2 = anglelist(n,1); @@ -302,8 +302,8 @@ void AngleHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i, const F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.template view(); - Kokkos::View > v_vatom = k_vatom.template view(); + 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) { diff --git a/src/KOKKOS/bond_class2_kokkos.h b/src/KOKKOS/bond_class2_kokkos.h index a31ae4b8ae..b3c1d5f682 100644 --- a/src/KOKKOS/bond_class2_kokkos.h +++ b/src/KOKKOS/bond_class2_kokkos.h @@ -63,13 +63,13 @@ class BondClass2Kokkos : public BondClass2 { class NeighborKokkos *neighborKK; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d bondlist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/bond_fene_kokkos.cpp b/src/KOKKOS/bond_fene_kokkos.cpp index 361bb61f7e..5f1e9d3ddc 100644 --- a/src/KOKKOS/bond_fene_kokkos.cpp +++ b/src/KOKKOS/bond_fene_kokkos.cpp @@ -166,7 +166,7 @@ void BondFENEKokkos::operator()(TagBondFENECompute > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = bondlist(n,0); const int i2 = bondlist(n,1); @@ -320,8 +320,8 @@ void BondFENEKokkos::ev_tally(EV_FLOAT &ev, const int &i, const int F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/bond_harmonic_kokkos.h b/src/KOKKOS/bond_harmonic_kokkos.h index 2bf12f3766..b5bee7e909 100644 --- a/src/KOKKOS/bond_harmonic_kokkos.h +++ b/src/KOKKOS/bond_harmonic_kokkos.h @@ -63,13 +63,13 @@ class BondHarmonicKokkos : public BondHarmonic { typedef ArrayTypes AT; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d bondlist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/dihedral_charmm_kokkos.cpp b/src/KOKKOS/dihedral_charmm_kokkos.cpp index 94fd0b9bb7..939834d096 100644 --- a/src/KOKKOS/dihedral_charmm_kokkos.cpp +++ b/src/KOKKOS/dihedral_charmm_kokkos.cpp @@ -201,7 +201,7 @@ KOKKOS_INLINE_FUNCTION void DihedralCharmmKokkos::operator()(TagDihedralCharmmCompute, const int &n, EVM_FLOAT& evm) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); diff --git a/src/KOKKOS/dihedral_charmm_kokkos.h b/src/KOKKOS/dihedral_charmm_kokkos.h index 449f934533..21bb6fd2e1 100644 --- a/src/KOKKOS/dihedral_charmm_kokkos.h +++ b/src/KOKKOS/dihedral_charmm_kokkos.h @@ -134,13 +134,13 @@ class DihedralCharmmKokkos : public DihedralCharmm { Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; Kokkos::DualView k_eatom_pair; Kokkos::DualView k_vatom_pair; - Kokkos::View > d_eatom_pair; - Kokkos::View > d_vatom_pair; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom_pair; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom_pair; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/dihedral_class2_kokkos.cpp b/src/KOKKOS/dihedral_class2_kokkos.cpp index 0310053b5e..60daca3137 100644 --- a/src/KOKKOS/dihedral_class2_kokkos.cpp +++ b/src/KOKKOS/dihedral_class2_kokkos.cpp @@ -197,7 +197,7 @@ KOKKOS_INLINE_FUNCTION void DihedralClass2Kokkos::operator()(TagDihedralClass2Compute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); @@ -1015,8 +1015,8 @@ void DihedralClass2Kokkos::ev_tally(EV_FLOAT &ev, const int i1, cons F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/dihedral_harmonic_kokkos.cpp b/src/KOKKOS/dihedral_harmonic_kokkos.cpp index dd77bc605b..0ed739ef38 100644 --- a/src/KOKKOS/dihedral_harmonic_kokkos.cpp +++ b/src/KOKKOS/dihedral_harmonic_kokkos.cpp @@ -158,7 +158,7 @@ KOKKOS_INLINE_FUNCTION void DihedralHarmonicKokkos::operator()(TagDihedralHarmonicCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); @@ -414,8 +414,8 @@ void DihedralHarmonicKokkos::ev_tally(EV_FLOAT &ev, const int i1, co F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/dihedral_opls_kokkos.cpp b/src/KOKKOS/dihedral_opls_kokkos.cpp index 825d106e04..0f510e01ad 100644 --- a/src/KOKKOS/dihedral_opls_kokkos.cpp +++ b/src/KOKKOS/dihedral_opls_kokkos.cpp @@ -157,7 +157,7 @@ KOKKOS_INLINE_FUNCTION void DihedralOPLSKokkos::operator()(TagDihedralOPLSCompute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; const int i1 = dihedrallist(n,0); const int i2 = dihedrallist(n,1); @@ -419,8 +419,8 @@ void DihedralOPLSKokkos::ev_tally(EV_FLOAT &ev, const int i1, const F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/fix_qeq_reax_kokkos.h b/src/KOKKOS/fix_qeq_reax_kokkos.h index cd69aa9283..55dec64d33 100644 --- a/src/KOKKOS/fix_qeq_reax_kokkos.h +++ b/src/KOKKOS/fix_qeq_reax_kokkos.h @@ -200,8 +200,8 @@ class FixQEqReaxKokkos : public FixQEqReax { HAT::t_ffloat_2d h_s_hist, h_t_hist; typename AT::t_ffloat_2d_randomread r_s_hist, r_t_hist; - Kokkos::Experimental::ScatterView dup_o; - Kokkos::Experimental::ScatterView ndup_o; + Kokkos::Experimental::ScatterView::value, Kokkos::Experimental::ScatterSum, Kokkos::Experimental::ScatterDuplicated> dup_o; + Kokkos::Experimental::ScatterView::value, Kokkos::Experimental::ScatterSum, Kokkos::Experimental::ScatterNonDuplicated> ndup_o; void init_shielding_k(); void init_hist(); diff --git a/src/KOKKOS/fix_rx_kokkos.cpp b/src/KOKKOS/fix_rx_kokkos.cpp index dcb1ac0b71..9271cf1b88 100644 --- a/src/KOKKOS/fix_rx_kokkos.cpp +++ b/src/KOKKOS/fix_rx_kokkos.cpp @@ -1908,7 +1908,7 @@ void FixRxKokkos::operator()(Tag_FixRxKokkos_firstPairOperator::value> > AtomicViewType; + typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, typename KKDevice::value, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; AtomicViewType a_dpdThetaLocal = d_dpdThetaLocal; AtomicViewType a_sumWeights = d_sumWeights; @@ -2083,8 +2083,8 @@ void FixRxKokkos::computeLocalTemperature() { // Create an atomic view of sumWeights and dpdThetaLocal. Only needed // for Half/thread scenarios. - //typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, DeviceType, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; - typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, DeviceType, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; + //typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, typename KKDevice::value, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; + typedef Kokkos::View< E_FLOAT*, typename DAT::t_efloat_1d::array_layout, typename KKDevice::value, Kokkos::MemoryTraits< AtomicF< NEIGHFLAG >::value> > AtomicViewType; AtomicViewType a_dpdThetaLocal = d_dpdThetaLocal; AtomicViewType a_sumWeights = d_sumWeights; diff --git a/src/KOKKOS/improper_class2_kokkos.cpp b/src/KOKKOS/improper_class2_kokkos.cpp index defd5e16f5..888f526c76 100644 --- a/src/KOKKOS/improper_class2_kokkos.cpp +++ b/src/KOKKOS/improper_class2_kokkos.cpp @@ -188,7 +188,7 @@ KOKKOS_INLINE_FUNCTION void ImproperClass2Kokkos::operator()(TagImproperClass2Compute, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; int i, j, k; F_FLOAT delr[3][3],rmag[3],rinvmag[3],rmag2[3]; @@ -660,7 +660,7 @@ KOKKOS_INLINE_FUNCTION void ImproperClass2Kokkos::operator()(TagImproperClass2AngleAngle, const int &n, EV_FLOAT& ev) const { // The f array is atomic - Kokkos::View > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits > a_f = f; int i,j,k; F_FLOAT eimproper; @@ -1010,8 +1010,8 @@ void ImproperClass2Kokkos::ev_tally(EV_FLOAT &ev, const int i1, cons F_FLOAT v[6]; // The eatom and vatom arrays are atomic - Kokkos::View > v_eatom = k_eatom.view(); - Kokkos::View > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits > v_vatom = k_vatom.view(); if (eflag_either) { if (eflag_global) { diff --git a/src/KOKKOS/improper_class2_kokkos.h b/src/KOKKOS/improper_class2_kokkos.h index 0fbfab2beb..11212249e7 100644 --- a/src/KOKKOS/improper_class2_kokkos.h +++ b/src/KOKKOS/improper_class2_kokkos.h @@ -75,7 +75,7 @@ class ImproperClass2Kokkos : public ImproperClass2 { class NeighborKokkos *neighborKK; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d improperlist; DAT::tdual_efloat_1d k_eatom; diff --git a/src/KOKKOS/improper_harmonic_kokkos.h b/src/KOKKOS/improper_harmonic_kokkos.h index 23ae0c7110..fb44081928 100644 --- a/src/KOKKOS/improper_harmonic_kokkos.h +++ b/src/KOKKOS/improper_harmonic_kokkos.h @@ -64,13 +64,13 @@ class ImproperHarmonicKokkos : public ImproperHarmonic { class NeighborKokkos *neighborKK; typename AT::t_x_array_randomread x; - typename Kokkos::View > f; + typename Kokkos::View::value,Kokkos::MemoryTraits > f; typename AT::t_int_2d improperlist; Kokkos::DualView k_eatom; Kokkos::DualView k_vatom; - Kokkos::View > d_eatom; - Kokkos::View > d_vatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_eatom; + Kokkos::View::value,Kokkos::MemoryTraits > d_vatom; int nlocal,newton_bond; int eflag,vflag; diff --git a/src/KOKKOS/kokkos_type.h b/src/KOKKOS/kokkos_type.h index 3ba6318d41..b1d17b45c3 100644 --- a/src/KOKKOS/kokkos_type.h +++ b/src/KOKKOS/kokkos_type.h @@ -163,6 +163,20 @@ t_scalar3 operator * typedef Kokkos::DefaultExecutionSpace LMPDeviceType; typedef Kokkos::HostSpace::execution_space LMPHostType; + +// Need to use Cuda UVM memory space for Host execution space + +template +class KKDevice { +public: +#if defined(KOKKOS_ENABLE_CUDA) && defined(KOKKOS_ENABLE_CUDA_UVM) + typedef Kokkos::Device value; +#else + typedef Kokkos::Device value; +#endif +}; + + // set ExecutionSpace stuct with variable "space" template diff --git a/src/KOKKOS/pair_coul_dsf_kokkos.cpp b/src/KOKKOS/pair_coul_dsf_kokkos.cpp index f7bf8fb5d1..cabdcfd455 100644 --- a/src/KOKKOS/pair_coul_dsf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_dsf_kokkos.cpp @@ -227,8 +227,8 @@ KOKKOS_INLINE_FUNCTION void PairCoulDSFKokkos::operator()(TagPairCoulDSFKernelA, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); const int i = d_ilist[ii]; const X_FLOAT xtmp = x(i,0); @@ -323,8 +323,8 @@ void PairCoulDSFKokkos::ev_tally(EV_FLOAT &ev, const int &i, const i const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_coul_wolf_kokkos.cpp b/src/KOKKOS/pair_coul_wolf_kokkos.cpp index f3ffdc6069..45c4ec3f22 100644 --- a/src/KOKKOS/pair_coul_wolf_kokkos.cpp +++ b/src/KOKKOS/pair_coul_wolf_kokkos.cpp @@ -228,8 +228,8 @@ KOKKOS_INLINE_FUNCTION void PairCoulWolfKokkos::operator()(TagPairCoulWolfKernelA, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); const int i = d_ilist[ii]; const X_FLOAT xtmp = x(i,0); @@ -325,8 +325,8 @@ void PairCoulWolfKokkos::ev_tally(EV_FLOAT &ev, const int &i, const const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp index 1ddf950fd7..3a1e02037a 100644 --- a/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp +++ b/src/KOKKOS/pair_dpd_fdt_energy_kokkos.cpp @@ -389,7 +389,7 @@ KOKKOS_INLINE_FUNCTION void PairDPDfdtEnergyKokkos::operator()(TagPairDPDfdtEnergyComputeSplit, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; @@ -473,9 +473,9 @@ KOKKOS_INLINE_FUNCTION void PairDPDfdtEnergyKokkos::operator()(TagPairDPDfdtEnergyComputeNoSplit, const int &ii, EV_FLOAT& ev) const { // These array are atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > a_duCond = d_duCond; - Kokkos::View::value> > a_duMech = d_duMech; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_duCond = d_duCond; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_duMech = d_duMech; int i,j,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,fpair; @@ -697,8 +697,8 @@ void PairDPDfdtEnergyKokkos::ev_tally(EV_FLOAT &ev, const int &i, co const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_eam_alloy_kokkos.h b/src/KOKKOS/pair_eam_alloy_kokkos.h index e1dd9ab47d..5796bdd1d4 100644 --- a/src/KOKKOS/pair_eam_alloy_kokkos.h +++ b/src/KOKKOS/pair_eam_alloy_kokkos.h @@ -129,14 +129,14 @@ class PairEAMAlloyKokkos : public PairEAM, public KokkosBase { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_rho; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_rho; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; DAT::tdual_ffloat_1d k_rho; DAT::tdual_ffloat_1d k_fp; diff --git a/src/KOKKOS/pair_eam_fs_kokkos.h b/src/KOKKOS/pair_eam_fs_kokkos.h index e93977869e..64e1c78d56 100644 --- a/src/KOKKOS/pair_eam_fs_kokkos.h +++ b/src/KOKKOS/pair_eam_fs_kokkos.h @@ -129,14 +129,14 @@ class PairEAMFSKokkos : public PairEAM, public KokkosBase { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_rho; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_rho; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; DAT::tdual_ffloat_1d k_rho; DAT::tdual_ffloat_1d k_fp; diff --git a/src/KOKKOS/pair_eam_kokkos.h b/src/KOKKOS/pair_eam_kokkos.h index 3bf89c549a..20bac4ed16 100644 --- a/src/KOKKOS/pair_eam_kokkos.h +++ b/src/KOKKOS/pair_eam_kokkos.h @@ -126,14 +126,14 @@ class PairEAMKokkos : public PairEAM, public KokkosBase { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_rho; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_rho; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_rho; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; DAT::tdual_ffloat_1d k_rho; DAT::tdual_ffloat_1d k_fp; diff --git a/src/KOKKOS/pair_exp6_rx_kokkos.cpp b/src/KOKKOS/pair_exp6_rx_kokkos.cpp index 4d72c85029..800ea81fa5 100644 --- a/src/KOKKOS/pair_exp6_rx_kokkos.cpp +++ b/src/KOKKOS/pair_exp6_rx_kokkos.cpp @@ -442,9 +442,9 @@ void PairExp6rxKokkos::operator()(TagPairExp6rxCompute::value> > a_f = f; - Kokkos::View::value> > a_uCG = uCG; - Kokkos::View::value> > a_uCGnew = uCGnew; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCG = uCG; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCGnew = uCGnew; int i,jj,jnum,itype,jtype; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,fpair; @@ -1183,9 +1183,9 @@ KOKKOS_INLINE_FUNCTION void PairExp6rxKokkos::vectorized_operator(const int &ii, EV_FLOAT& ev) const { // These arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > a_uCG = uCG; - Kokkos::View::value> > a_uCGnew = uCGnew; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCG = uCG; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_uCGnew = uCGnew; int tid = 0; #ifndef KOKKOS_ENABLE_CUDA @@ -2562,8 +2562,8 @@ void PairExp6rxKokkos::ev_tally(EV_FLOAT &ev, const int &i, const in const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp index 9e65c0589e..8797aab71e 100644 --- a/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp +++ b/src/KOKKOS/pair_gran_hooke_history_kokkos.cpp @@ -320,8 +320,8 @@ KOKKOS_INLINE_FUNCTION void PairGranHookeHistoryKokkos::operator()(TagPairGranHookeHistoryCompute, const int ii, EV_FLOAT &ev) const { // The f and torque arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; - Kokkos::View::value> > a_torque = torque; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_torque = torque; const int i = d_ilist[ii]; const X_FLOAT xtmp = x(i,0); @@ -549,7 +549,7 @@ void PairGranHookeHistoryKokkos::ev_tally_xyz_atom(EV_FLOAT &ev, int F_FLOAT fx, F_FLOAT fy, F_FLOAT fz, X_FLOAT delx, X_FLOAT dely, X_FLOAT delz) const { - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); F_FLOAT v[6]; diff --git a/src/KOKKOS/pair_kokkos.h b/src/KOKKOS/pair_kokkos.h index 41922b7349..54035c54eb 100644 --- a/src/KOKKOS/pair_kokkos.h +++ b/src/KOKKOS/pair_kokkos.h @@ -66,17 +66,17 @@ struct PairComputeFunctor { // The force array is atomic for Half/Thread neighbor style //Kokkos::View::value> > f; - Kokkos::Experimental::ScatterView::value > dup_f; + // typename KKDevice::value,Kokkos::MemoryTraits::value> > f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,NeedDup::value > dup_f; // The eatom and vatom arrays are atomic for Half/Thread neighbor style //Kokkos::View::value> > eatom; - Kokkos::Experimental::ScatterView::value > dup_eatom; + // typename KKDevice::value,Kokkos::MemoryTraits::value> > eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,NeedDup::value > dup_eatom; //Kokkos::View::value> > vatom; - Kokkos::Experimental::ScatterView::value > dup_vatom; + // typename KKDevice::value,Kokkos::MemoryTraits::value> > vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,NeedDup::value > dup_vatom; diff --git a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp index 3b7a738026..1c125b4dc0 100644 --- a/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp +++ b/src/KOKKOS/pair_multi_lucy_rx_kokkos.cpp @@ -270,7 +270,7 @@ KOKKOS_INLINE_FUNCTION void PairMultiLucyRXKokkos::operator()(TagPairMultiLucyRXCompute, const int &ii, EV_FLOAT& ev) const { // The f array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; int i,jj,jnum,itype,jtype,itable; double xtmp,ytmp,ztmp,delx,dely,delz,evdwl,evdwlOld,fpair; @@ -532,7 +532,7 @@ void PairMultiLucyRXKokkos::operator()(TagPairMultiLucyRXComputeLoca // The rho array is atomic for Half/Thread neighbor style - Kokkos::View::value> > a_rho = rho; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_rho = rho; const int i = d_ilist[ii]; @@ -771,8 +771,8 @@ void PairMultiLucyRXKokkos::ev_tally(EV_FLOAT &ev, const int &i, con const int VFLAG = vflag_either; // The eatom and vatom arrays are atomic for Half/Thread neighbor style - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (EFLAG) { if (eflag_atom) { diff --git a/src/KOKKOS/pair_reaxc_kokkos.cpp b/src/KOKKOS/pair_reaxc_kokkos.cpp index 18144bb653..302ecbafd9 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.cpp +++ b/src/KOKKOS/pair_reaxc_kokkos.cpp @@ -2477,7 +2477,7 @@ void PairReaxCKokkos::operator()(PairReaxComputeAngular::value,decltype(dup_f),decltype(ndup_f)>::get(dup_f,ndup_f); auto a_f = v_f.template access::value>(); - Kokkos::View::value> > a_Cdbo = d_Cdbo; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbo = d_Cdbo; auto v_CdDelta = ScatterViewHelper::value,decltype(dup_CdDelta),decltype(ndup_CdDelta)>::get(dup_CdDelta,ndup_CdDelta); auto a_CdDelta = v_CdDelta.template access::value>(); @@ -2792,7 +2792,7 @@ void PairReaxCKokkos::operator()(PairReaxComputeTorsion::value,decltype(dup_CdDelta),decltype(ndup_CdDelta)>::get(dup_CdDelta,ndup_CdDelta); auto a_CdDelta = v_CdDelta.template access::value>(); - Kokkos::View::value> > a_Cdbo = d_Cdbo; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbo = d_Cdbo; //auto a_Cdbo = dup_Cdbo.template access::value>(); // in reaxc_torsion_angles: j = i, k = j, i = k; @@ -3311,9 +3311,9 @@ template KOKKOS_INLINE_FUNCTION void PairReaxCKokkos::operator()(PairReaxUpdateBond, const int &ii) const { - Kokkos::View::value> > a_Cdbo = d_Cdbo; - Kokkos::View::value> > a_Cdbopi = d_Cdbopi; - Kokkos::View::value> > a_Cdbopi2 = d_Cdbopi2; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbo = d_Cdbo; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbopi = d_Cdbopi; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_Cdbopi2 = d_Cdbopi2; //auto a_Cdbo = dup_Cdbo.template access::value>(); //auto a_Cdbopi = dup_Cdbopi.template access::value>(); //auto a_Cdbopi2 = dup_Cdbopi2.template access::value>(); diff --git a/src/KOKKOS/pair_reaxc_kokkos.h b/src/KOKKOS/pair_reaxc_kokkos.h index 783ea33c4e..93ca4468ec 100644 --- a/src/KOKKOS/pair_reaxc_kokkos.h +++ b/src/KOKKOS/pair_reaxc_kokkos.h @@ -399,25 +399,25 @@ class PairReaxCKokkos : public PairReaxC { typename AT::t_ffloat_2d_dl d_C1dbopi2, d_C2dbopi2, d_C3dbopi2, d_C4dbopi2; typename AT::t_ffloat_2d_dl d_Cdbo, d_Cdbopi, d_Cdbopi2, d_dDeltap_self; - Kokkos::Experimental::ScatterView dup_total_bo; - Kokkos::Experimental::ScatterView dup_CdDelta; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView dup_dDeltap_self; - Kokkos::Experimental::ScatterView dup_Cdbo; - Kokkos::Experimental::ScatterView dup_Cdbopi; - Kokkos::Experimental::ScatterView dup_Cdbopi2; - - Kokkos::Experimental::ScatterView ndup_total_bo; - Kokkos::Experimental::ScatterView ndup_CdDelta; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_vatom; - Kokkos::Experimental::ScatterView ndup_dDeltap_self; - Kokkos::Experimental::ScatterView ndup_Cdbo; - Kokkos::Experimental::ScatterView ndup_Cdbopi; - Kokkos::Experimental::ScatterView ndup_Cdbopi2; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_total_bo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_CdDelta; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_dDeltap_self; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_Cdbo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_Cdbopi; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_Cdbopi2; + + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_total_bo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_CdDelta; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_dDeltap_self; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_Cdbo; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_Cdbopi; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_Cdbopi2; int need_dup; diff --git a/src/KOKKOS/pair_snap_kokkos.h b/src/KOKKOS/pair_snap_kokkos.h index b57ef2d9e5..1fbb537f35 100644 --- a/src/KOKKOS/pair_snap_kokkos.h +++ b/src/KOKKOS/pair_snap_kokkos.h @@ -181,10 +181,10 @@ inline double dist2(double* x,double* y); typename AT::t_int_1d_randomread type; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; friend void pair_virial_fdotr_compute(PairSNAPKokkos*); diff --git a/src/KOKKOS/pair_sw_kokkos.h b/src/KOKKOS/pair_sw_kokkos.h index 1a3f0b862f..2fc7f93c12 100644 --- a/src/KOKKOS/pair_sw_kokkos.h +++ b/src/KOKKOS/pair_sw_kokkos.h @@ -135,12 +135,12 @@ class PairSWKokkos : public PairSW { typename AT::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typename AT::t_int_1d_randomread d_type2frho; typename AT::t_int_2d_randomread d_type2rhor; diff --git a/src/KOKKOS/pair_table_rx_kokkos.cpp b/src/KOKKOS/pair_table_rx_kokkos.cpp index cd7aa373ed..687489791e 100644 --- a/src/KOKKOS/pair_table_rx_kokkos.cpp +++ b/src/KOKKOS/pair_table_rx_kokkos.cpp @@ -284,11 +284,11 @@ ev_tally( F_FLOAT delx, F_FLOAT dely, F_FLOAT delz, Kokkos::View::t_virial_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_vatom, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_eatom) { if (eflag) { @@ -399,15 +399,15 @@ compute_item( typename ArrayTypes::t_ffloat_2d const& d_cutsq, Kokkos::View::t_f_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& f, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& uCG, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& uCGnew, int isite1, int isite2, typename PairTableRXKokkos::TableDeviceConst const& d_table_const, @@ -418,11 +418,11 @@ compute_item( int vflag_atom, Kokkos::View::t_virial_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_vatom, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > const& v_eatom) { EV_FLOAT ev; auto i = d_ilist(ii); @@ -544,14 +544,16 @@ static void compute_all_items( typename ArrayTypes::t_ffloat_2d d_cutsq, Kokkos::View::t_f_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > f, Kokkos::View::t_efloat_1d::array_layout, - DeviceType,Kokkos::MemoryTraits::value> > uCG, + typename KKDevice::value, + Kokkos::MemoryTraits::value> > uCG, Kokkos::View::t_efloat_1d::array_layout, - DeviceType,Kokkos::MemoryTraits::value> > uCGnew, + typename KKDevice::value, + Kokkos::MemoryTraits::value> > uCGnew, int isite1, int isite2, typename PairTableRXKokkos::TableDeviceConst d_table_const, int eflag, @@ -561,11 +563,11 @@ static void compute_all_items( int vflag_atom, Kokkos::View::t_virial_array::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > v_vatom, Kokkos::View::t_efloat_1d::array_layout, - DeviceType, + typename KKDevice::value, Kokkos::MemoryTraits::value> > v_eatom) { if (eflag || vflag) { Kokkos::parallel_reduce(inum, diff --git a/src/KOKKOS/pair_tersoff_kokkos.h b/src/KOKKOS/pair_tersoff_kokkos.h index 7d41fe2346..0c57e21a6c 100644 --- a/src/KOKKOS/pair_tersoff_kokkos.h +++ b/src/KOKKOS/pair_tersoff_kokkos.h @@ -202,12 +202,12 @@ class PairTersoffKokkos : public PairTersoff { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typedef Kokkos::DualView tdual_ffloat_2d_n7; typedef typename tdual_ffloat_2d_n7::t_dev_const_randomread t_ffloat_2d_n7_randomread; diff --git a/src/KOKKOS/pair_tersoff_mod_kokkos.h b/src/KOKKOS/pair_tersoff_mod_kokkos.h index 889e1eadfa..b47f11e029 100644 --- a/src/KOKKOS/pair_tersoff_mod_kokkos.h +++ b/src/KOKKOS/pair_tersoff_mod_kokkos.h @@ -202,12 +202,12 @@ class PairTersoffMODKokkos : public PairTersoffMOD { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typedef Kokkos::DualView tdual_ffloat_2d_n7; typedef typename tdual_ffloat_2d_n7::t_dev_const_randomread t_ffloat_2d_n7_randomread; diff --git a/src/KOKKOS/pair_tersoff_zbl_kokkos.h b/src/KOKKOS/pair_tersoff_zbl_kokkos.h index 0c7fa2e963..bed2564da5 100644 --- a/src/KOKKOS/pair_tersoff_zbl_kokkos.h +++ b/src/KOKKOS/pair_tersoff_zbl_kokkos.h @@ -207,12 +207,12 @@ class PairTersoffZBLKokkos : public PairTersoffZBL { typename ArrayTypes::t_virial_array d_vatom; int need_dup; - Kokkos::Experimental::ScatterView dup_f; - Kokkos::Experimental::ScatterView dup_eatom; - Kokkos::Experimental::ScatterView dup_vatom; - Kokkos::Experimental::ScatterView ndup_f; - Kokkos::Experimental::ScatterView ndup_eatom; - Kokkos::Experimental::ScatterView ndup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterDuplicated> dup_vatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_f; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_eatom; + Kokkos::Experimental::ScatterView::value,Kokkos::Experimental::ScatterSum,Kokkos::Experimental::ScatterNonDuplicated> ndup_vatom; typedef Kokkos::DualView tdual_ffloat_2d_n7; typedef typename tdual_ffloat_2d_n7::t_dev_const_randomread t_ffloat_2d_n7_randomread; diff --git a/src/KOKKOS/pair_vashishta_kokkos.cpp b/src/KOKKOS/pair_vashishta_kokkos.cpp index ddb0688e03..84887fa1f0 100644 --- a/src/KOKKOS/pair_vashishta_kokkos.cpp +++ b/src/KOKKOS/pair_vashishta_kokkos.cpp @@ -234,7 +234,7 @@ void PairVashishtaKokkos::operator()(TagPairVashishtaComputeHalf::value> > a_f = f; + Kokkos::View::value,Kokkos::MemoryTraits::value> > a_f = f; F_FLOAT delr1[3],delr2[3],fj[3],fk[3]; F_FLOAT evdwl = 0.0; @@ -780,8 +780,8 @@ void PairVashishtaKokkos::ev_tally(EV_FLOAT &ev, const int &i, const // The eatom and vatom arrays are atomic for half/thread neighbor list - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (eflag_atom) { @@ -856,8 +856,8 @@ void PairVashishtaKokkos::ev_tally3(EV_FLOAT &ev, const int &i, cons // The eatom and vatom arrays are atomic for half/thread neighbor list - Kokkos::View::value> > v_eatom = k_eatom.view(); - Kokkos::View::value> > v_vatom = k_vatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_eatom = k_eatom.view(); + Kokkos::View::value,Kokkos::MemoryTraits::value> > v_vatom = k_vatom.view(); if (eflag_atom) { epairthird = THIRD * (evdwl + ecoul); diff --git a/src/KOKKOS/pppm_kokkos.cpp b/src/KOKKOS/pppm_kokkos.cpp index 08a0c18f9c..b0f6f393cf 100644 --- a/src/KOKKOS/pppm_kokkos.cpp +++ b/src/KOKKOS/pppm_kokkos.cpp @@ -1670,7 +1670,7 @@ KOKKOS_INLINE_FUNCTION void PPPMKokkos::operator()(TagPPPM_make_rho_atomic, const int &i) const { // The density_brick array is atomic for Half/Thread neighbor style - Kokkos::View > a_density_brick = d_density_brick; + Kokkos::View::value,Kokkos::MemoryTraits > a_density_brick = d_density_brick; int nx = d_part2grid(i,0); int ny = d_part2grid(i,1); diff --git a/src/KOKKOS/sna_kokkos.h b/src/KOKKOS/sna_kokkos.h index a6d9db3218..b7162cf8d6 100644 --- a/src/KOKKOS/sna_kokkos.h +++ b/src/KOKKOS/sna_kokkos.h @@ -89,7 +89,7 @@ class SNAKokkos { public: typedef Kokkos::View t_sna_1i; typedef Kokkos::View t_sna_1d; - typedef Kokkos::View > t_sna_1d_atomic; + typedef Kokkos::View::value, Kokkos::MemoryTraits > t_sna_1d_atomic; typedef Kokkos::View t_sna_2i; typedef Kokkos::View t_sna_2d; typedef Kokkos::View t_sna_2d_ll; @@ -99,7 +99,7 @@ public: typedef Kokkos::View t_sna_5d; typedef Kokkos::View t_sna_1c; - typedef Kokkos::View > t_sna_1c_atomic; + typedef Kokkos::View::value, Kokkos::MemoryTraits > t_sna_1c_atomic; typedef Kokkos::View t_sna_2c; typedef Kokkos::View t_sna_2c_ll; typedef Kokkos::View t_sna_2c_lr; -- GitLab From 60864e38d1d5f34db0ff379bf71eab0da0ca1ed0 Mon Sep 17 00:00:00 2001 From: Stan Moore Date: Wed, 25 Mar 2020 14:08:39 -0600 Subject: [PATCH 100/577] Update Kokkos library in LAMMPS to v3.0 --- lib/kokkos/BUILD.md | 323 + lib/kokkos/CHANGELOG.md | 40 + lib/kokkos/CMakeLists.txt | 327 +- lib/kokkos/CONTRIBUTING.md | 14 + lib/kokkos/Copyright.txt | 11 +- lib/kokkos/LICENSE | 11 +- lib/kokkos/Makefile.kokkos | 132 +- lib/kokkos/Makefile.targets | 2 + lib/kokkos/README | 193 - lib/kokkos/README.md | 299 + lib/kokkos/algorithms/CMakeLists.txt | 24 +- lib/kokkos/algorithms/src/CMakeLists.txt | 27 +- lib/kokkos/algorithms/src/Kokkos_Random.hpp | 2683 ++++---- lib/kokkos/algorithms/src/Kokkos_Sort.hpp | 667 +- .../algorithms/unit_tests/CMakeLists.txt | 39 +- lib/kokkos/algorithms/unit_tests/TestCuda.cpp | 55 +- lib/kokkos/algorithms/unit_tests/TestHPX.cpp | 53 +- .../algorithms/unit_tests/TestOpenMP.cpp | 51 +- lib/kokkos/algorithms/unit_tests/TestROCm.cpp | 62 +- .../algorithms/unit_tests/TestRandom.hpp | 511 +- .../algorithms/unit_tests/TestSerial.cpp | 54 +- lib/kokkos/algorithms/unit_tests/TestSort.hpp | 298 +- .../algorithms/unit_tests/TestThreads.cpp | 54 +- .../algorithms/unit_tests/UnitTestMain.cpp | 16 +- lib/kokkos/benchmarks/atomic/main.cpp | 202 +- .../benchmarks/bytes_and_flops/bench.hpp | 72 +- .../bytes_and_flops/bench_stride.hpp | 121 +- .../bytes_and_flops/bench_unroll_stride.hpp | 181 +- .../benchmarks/bytes_and_flops/main.cpp | 54 +- lib/kokkos/benchmarks/gather/gather.hpp | 55 +- .../benchmarks/gather/gather_unroll.hpp | 202 +- lib/kokkos/benchmarks/gather/main.cpp | 54 +- lib/kokkos/benchmarks/gups/gups-kokkos.cc | 11 +- .../benchmarks/policy_performance/main.cpp | 179 +- .../policy_performance/policy_perf_test.hpp | 570 +- .../policy_performance/script_sample_usage.sh | 2 +- lib/kokkos/benchmarks/stream/stream-kokkos.cc | 11 +- lib/kokkos/bin/hpcbind | 2 +- lib/kokkos/bin/nvcc_wrapper | 77 +- lib/kokkos/cm_generate_makefile.bash | 339 + lib/kokkos/cmake/KokkosConfig.cmake.in | 26 +- lib/kokkos/cmake/KokkosConfigCommon.cmake.in | 87 + lib/kokkos/cmake/KokkosCore_config.h.in | 89 + .../cmake/Makefile.generate_cmake_settings | 8 - lib/kokkos/cmake/Modules/FindHWLOC.cmake | 20 - lib/kokkos/cmake/Modules/FindMemkind.cmake | 20 - lib/kokkos/cmake/Modules/FindQthreads.cmake | 20 - lib/kokkos/cmake/Modules/FindTPLCUDA.cmake | 13 + lib/kokkos/cmake/Modules/FindTPLHPX.cmake | 15 + lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake | 1 + lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake | 17 + lib/kokkos/cmake/README.md | 331 + lib/kokkos/cmake/compile_tests/clang_omp.cpp | 9 + lib/kokkos/cmake/compile_tests/pthread.cpp | 10 + lib/kokkos/cmake/cray.cmake | 9 + lib/kokkos/cmake/deps/CUDA.cmake | 2 +- lib/kokkos/cmake/deps/CUSPARSE.cmake | 2 +- lib/kokkos/cmake/deps/HWLOC.cmake | 2 +- lib/kokkos/cmake/deps/Pthread.cmake | 4 +- lib/kokkos/cmake/deps/QTHREADS.cmake | 69 - lib/kokkos/cmake/fake_tribits.cmake | 338 + lib/kokkos/cmake/gnu.cmake | 23 + lib/kokkos/cmake/intel.cmake | 30 + lib/kokkos/cmake/kokkos_arch.cmake | 438 ++ lib/kokkos/cmake/kokkos_build.cmake | 261 - lib/kokkos/cmake/kokkos_compiler_id.cmake | 80 + lib/kokkos/cmake/kokkos_corner_cases.cmake | 35 + lib/kokkos/cmake/kokkos_enable_devices.cmake | 61 + lib/kokkos/cmake/kokkos_enable_options.cmake | 92 + lib/kokkos/cmake/kokkos_functions.cmake | 1033 ++- lib/kokkos/cmake/kokkos_install.cmake | 42 + lib/kokkos/cmake/kokkos_options.cmake | 419 -- lib/kokkos/cmake/kokkos_pick_cxx_std.cmake | 46 + lib/kokkos/cmake/kokkos_settings.cmake | 259 - lib/kokkos/cmake/kokkos_test_cxx_std.cmake | 144 + lib/kokkos/cmake/kokkos_tpls.cmake | 47 + lib/kokkos/cmake/kokkos_tribits.cmake | 392 ++ lib/kokkos/cmake/pgi.cmake | 8 + lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake | 2 +- lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake | 2 +- lib/kokkos/cmake/tpls/FindTPLPthread.cmake | 2 +- lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake | 69 - lib/kokkos/cmake/tribits.cmake | 531 -- lib/kokkos/containers/CMakeLists.txt | 23 +- .../performance_tests/CMakeLists.txt | 91 +- .../containers/performance_tests/TestCuda.cpp | 48 +- .../performance_tests/TestDynRankView.hpp | 159 +- .../performance_tests/TestGlobal2LocalIds.hpp | 138 +- .../containers/performance_tests/TestHPX.cpp | 68 +- .../containers/performance_tests/TestMain.cpp | 14 +- .../performance_tests/TestOpenMP.cpp | 79 +- .../containers/performance_tests/TestROCm.cpp | 38 +- .../performance_tests/TestScatterView.hpp | 112 +- .../performance_tests/TestThreads.cpp | 55 +- .../TestUnorderedMapPerformance.hpp | 100 +- lib/kokkos/containers/src/CMakeLists.txt | 81 +- lib/kokkos/containers/src/Kokkos_Bitset.hpp | 348 +- lib/kokkos/containers/src/Kokkos_DualView.hpp | 830 +-- .../containers/src/Kokkos_DynRankView.hpp | 3176 +++++----- .../containers/src/Kokkos_DynamicView.hpp | 719 +-- .../containers/src/Kokkos_ErrorReporter.hpp | 111 +- .../containers/src/Kokkos_Functional.hpp | 85 +- .../containers/src/Kokkos_OffsetView.hpp | 3802 +++++------ .../containers/src/Kokkos_ScatterView.hpp | 1535 +++-- .../containers/src/Kokkos_StaticCrsGraph.hpp | 430 +- .../containers/src/Kokkos_UnorderedMap.hpp | 621 +- lib/kokkos/containers/src/Kokkos_Vector.hpp | 294 +- .../src/impl/Kokkos_Bitset_impl.hpp | 60 +- .../src/impl/Kokkos_Functional_impl.hpp | 113 +- .../impl/Kokkos_StaticCrsGraph_factory.hpp | 253 +- .../src/impl/Kokkos_UnorderedMap_impl.cpp | 105 +- .../src/impl/Kokkos_UnorderedMap_impl.hpp | 169 +- .../containers/unit_tests/CMakeLists.txt | 171 +- .../containers/unit_tests/TestBitset.hpp | 183 +- .../containers/unit_tests/TestDualView.hpp | 271 +- .../containers/unit_tests/TestDynViewAPI.hpp | 2425 +++---- .../unit_tests/TestDynViewAPI_generic.hpp | 20 +- .../unit_tests/TestDynViewAPI_rank12345.hpp | 20 +- .../unit_tests/TestDynViewAPI_rank67.hpp | 20 +- .../containers/unit_tests/TestDynamicView.hpp | 259 +- .../unit_tests/TestErrorReporter.hpp | 146 +- .../containers/unit_tests/TestOffsetView.hpp | 933 ++- .../containers/unit_tests/TestScatterView.hpp | 672 +- .../unit_tests/TestStaticCrsGraph.hpp | 306 +- .../unit_tests/TestUnorderedMap.hpp | 276 +- .../containers/unit_tests/TestVector.hpp | 235 +- .../TestViewCtorPropEmbeddedDim.hpp | 173 +- .../containers/unit_tests/UnitTestMain.cpp | 17 +- .../unit_tests/cuda/TestCuda_BitSet.cpp | 16 +- .../unit_tests/cuda/TestCuda_Category.hpp | 26 +- .../unit_tests/cuda/TestCuda_DualView.cpp | 16 +- .../cuda/TestCuda_DynRankViewAPI_generic.cpp | 16 +- .../TestCuda_DynRankViewAPI_rank12345.cpp | 16 +- .../cuda/TestCuda_DynRankViewAPI_rank67.cpp | 16 +- .../unit_tests/cuda/TestCuda_DynamicView.cpp | 16 +- .../cuda/TestCuda_ErrorReporter.cpp | 16 +- .../unit_tests/cuda/TestCuda_OffsetView.cpp | 16 +- .../unit_tests/cuda/TestCuda_ScatterView.cpp | 16 +- .../cuda/TestCuda_StaticCrsGraph.cpp | 16 +- .../unit_tests/cuda/TestCuda_UnorderedMap.cpp | 16 +- .../unit_tests/cuda/TestCuda_Vector.cpp | 16 +- .../cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/hpx/TestHPX_BitSet.cpp | 16 +- .../unit_tests/hpx/TestHPX_Category.hpp | 26 +- .../unit_tests/hpx/TestHPX_DualView.cpp | 16 +- .../hpx/TestHPX_DynRankViewAPI_generic.cpp | 16 +- .../hpx/TestHPX_DynRankViewAPI_rank12345.cpp | 16 +- .../hpx/TestHPX_DynRankViewAPI_rank67.cpp | 16 +- .../unit_tests/hpx/TestHPX_DynamicView.cpp | 16 +- .../unit_tests/hpx/TestHPX_ErrorReporter.cpp | 16 +- .../unit_tests/hpx/TestHPX_OffsetView.cpp | 16 +- .../unit_tests/hpx/TestHPX_ScatterView.cpp | 16 +- .../unit_tests/hpx/TestHPX_StaticCrsGraph.cpp | 16 +- .../unit_tests/hpx/TestHPX_UnorderedMap.cpp | 16 +- .../unit_tests/hpx/TestHPX_Vector.cpp | 16 +- .../hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/openmp/TestOpenMP_BitSet.cpp | 16 +- .../unit_tests/openmp/TestOpenMP_Category.hpp | 26 +- .../unit_tests/openmp/TestOpenMP_DualView.cpp | 16 +- .../TestOpenMP_DynRankViewAPI_generic.cpp | 16 +- .../TestOpenMP_DynRankViewAPI_rank12345.cpp | 16 +- .../TestOpenMP_DynRankViewAPI_rank67.cpp | 16 +- .../openmp/TestOpenMP_DynamicView.cpp | 16 +- .../openmp/TestOpenMP_ErrorReporter.cpp | 16 +- .../openmp/TestOpenMP_OffsetView.cpp | 16 +- .../openmp/TestOpenMP_ScatterView.cpp | 16 +- .../openmp/TestOpenMP_StaticCrsGraph.cpp | 16 +- .../openmp/TestOpenMP_UnorderedMap.cpp | 16 +- .../unit_tests/openmp/TestOpenMP_Vector.cpp | 16 +- .../TestOpenMP_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/rocm/TestROCm_BitSet.cpp | 16 +- .../unit_tests/rocm/TestROCm_Category.hpp | 26 +- .../unit_tests/rocm/TestROCm_DualView.cpp | 16 +- .../rocm/TestROCm_DynRankViewAPI_generic.cpp | 16 +- .../TestROCm_DynRankViewAPI_rank12345.cpp | 16 +- .../rocm/TestROCm_DynRankViewAPI_rank67.cpp | 16 +- .../unit_tests/rocm/TestROCm_DynamicView.cpp | 16 +- .../rocm/TestROCm_ErrorReporter.cpp | 16 +- .../unit_tests/rocm/TestROCm_ScatterView.cpp | 16 +- .../rocm/TestROCm_StaticCrsGraph.cpp | 16 +- .../unit_tests/rocm/TestROCm_UnorderedMap.cpp | 16 +- .../unit_tests/rocm/TestROCm_Vector.cpp | 16 +- .../rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/serial/TestSerial_BitSet.cpp | 16 +- .../unit_tests/serial/TestSerial_Category.hpp | 26 +- .../unit_tests/serial/TestSerial_DualView.cpp | 16 +- .../TestSerial_DynRankViewAPI_generic.cpp | 16 +- .../TestSerial_DynRankViewAPI_rank12345.cpp | 16 +- .../TestSerial_DynRankViewAPI_rank67.cpp | 16 +- .../serial/TestSerial_DynamicView.cpp | 16 +- .../serial/TestSerial_ErrorReporter.cpp | 16 +- .../serial/TestSerial_OffsetView.cpp | 16 +- .../serial/TestSerial_ScatterView.cpp | 16 +- .../serial/TestSerial_StaticCrsGraph.cpp | 16 +- .../serial/TestSerial_UnorderedMap.cpp | 16 +- .../unit_tests/serial/TestSerial_Vector.cpp | 16 +- .../TestSerial_ViewCtorPropEmbeddedDim.cpp | 16 +- .../unit_tests/threads/TestThreads_BitSet.cpp | 16 +- .../threads/TestThreads_Category.hpp | 26 +- .../threads/TestThreads_DualView.cpp | 16 +- .../TestThreads_DynRankViewAPI_generic.cpp | 16 +- .../TestThreads_DynRankViewAPI_rank12345.cpp | 16 +- .../TestThreads_DynRankViewAPI_rank67.cpp | 16 +- .../threads/TestThreads_DynamicView.cpp | 16 +- .../threads/TestThreads_ErrorReporter.cpp | 16 +- .../threads/TestThreads_OffsetView.cpp | 16 +- .../threads/TestThreads_ScatterView.cpp | 16 +- .../threads/TestThreads_StaticCrsGraph.cpp | 16 +- .../threads/TestThreads_UnorderedMap.cpp | 16 +- .../unit_tests/threads/TestThreads_Vector.cpp | 16 +- .../TestThreads_ViewCtorPropEmbeddedDim.cpp | 16 +- lib/kokkos/core/CMakeLists.txt | 25 +- lib/kokkos/core/cmake/KokkosCore_config.h.in | 3 +- lib/kokkos/core/perf_test/CMakeLists.txt | 80 +- .../core/perf_test/PerfTestBlasKernels.hpp | 254 +- lib/kokkos/core/perf_test/PerfTestDriver.hpp | 545 +- .../core/perf_test/PerfTestGramSchmidt.cpp | 282 +- lib/kokkos/core/perf_test/PerfTestHexGrad.cpp | 437 +- lib/kokkos/core/perf_test/PerfTestMDRange.hpp | 762 +-- lib/kokkos/core/perf_test/PerfTestMain.cpp | 31 +- .../core/perf_test/PerfTest_Category.hpp | 22 +- .../perf_test/PerfTest_CustomReduction.cpp | 128 +- .../PerfTest_ExecSpacePartitioning.cpp | 1046 ++-- .../core/perf_test/PerfTest_ViewAllocate.cpp | 125 +- .../core/perf_test/PerfTest_ViewCopy.hpp | 268 +- .../core/perf_test/PerfTest_ViewCopy_a123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_a8.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_b8.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_c8.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d123.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d45.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d6.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d7.cpp | 19 +- .../core/perf_test/PerfTest_ViewCopy_d8.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill.hpp | 232 +- .../core/perf_test/PerfTest_ViewFill_123.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_45.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_6.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_7.cpp | 19 +- .../core/perf_test/PerfTest_ViewFill_8.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize.hpp | 381 +- .../perf_test/PerfTest_ViewResize_123.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_45.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_6.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_7.cpp | 19 +- .../core/perf_test/PerfTest_ViewResize_8.cpp | 19 +- lib/kokkos/core/perf_test/test_atomic.cpp | 460 +- lib/kokkos/core/perf_test/test_mempool.cpp | 360 +- lib/kokkos/core/perf_test/test_taskdag.cpp | 264 +- lib/kokkos/core/src/CMakeLists.txt | 205 +- .../src/Cuda/KokkosExp_Cuda_IterateTile.hpp | 1757 +++--- .../KokkosExp_Cuda_IterateTile_Refactor.hpp | 3352 +++++----- lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp | 1054 ++-- .../core/src/Cuda/Kokkos_Cuda_Alloc.hpp | 119 +- .../Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp | 1289 ++-- ...uda_Atomic_Intrinsics_Restore_Builtins.hpp | 10 +- .../Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp | 704 ++- .../core/src/Cuda/Kokkos_Cuda_Error.hpp | 91 +- .../core/src/Cuda/Kokkos_Cuda_Instance.cpp | 848 +-- .../core/src/Cuda/Kokkos_Cuda_Instance.hpp | 213 +- .../src/Cuda/Kokkos_Cuda_KernelLaunch.hpp | 599 +- .../core/src/Cuda/Kokkos_Cuda_Locks.cpp | 45 +- .../core/src/Cuda/Kokkos_Cuda_Locks.hpp | 92 +- .../core/src/Cuda/Kokkos_Cuda_Parallel.hpp | 3816 ++++++----- .../core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp | 1183 ++-- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp | 28 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp | 1115 ++-- lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp | 1119 ++-- .../core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp | 123 +- .../src/Cuda/Kokkos_Cuda_Vectorization.hpp | 484 +- .../Kokkos_Cuda_Version_9_8_Compatibility.hpp | 123 +- lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp | 330 +- .../src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp | 18 +- .../src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp | 18 +- .../src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp | 109 +- .../core/src/Cuda/Kokkos_Cuda_abort.hpp | 40 +- lib/kokkos/core/src/HPX/Kokkos_HPX.cpp | 31 +- .../Kokkos_HPX_ChunkedRoundRobinExecutor.hpp | 208 + lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp | 17 +- lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp | 81 +- .../src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp | 18 +- .../src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp | 18 +- .../src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp | 36 +- .../core/src/KokkosExp_MDRangePolicy.hpp | 727 +-- lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp | 74 +- lib/kokkos/core/src/Kokkos_Array.hpp | 426 +- lib/kokkos/core/src/Kokkos_Atomic.hpp | 118 +- lib/kokkos/core/src/Kokkos_Complex.hpp | 1000 ++- lib/kokkos/core/src/Kokkos_Concepts.hpp | 422 +- lib/kokkos/core/src/Kokkos_CopyViews.hpp | 4466 +++++++------ lib/kokkos/core/src/Kokkos_Core.hpp | 149 +- lib/kokkos/core/src/Kokkos_Core_fwd.hpp | 330 +- lib/kokkos/core/src/Kokkos_Crs.hpp | 331 +- lib/kokkos/core/src/Kokkos_Cuda.hpp | 175 +- lib/kokkos/core/src/Kokkos_CudaSpace.hpp | 936 ++- lib/kokkos/core/src/Kokkos_ExecPolicy.hpp | 1080 ++-- lib/kokkos/core/src/Kokkos_Extents.hpp | 110 +- lib/kokkos/core/src/Kokkos_Future.hpp | 495 +- lib/kokkos/core/src/Kokkos_HBWSpace.hpp | 272 +- lib/kokkos/core/src/Kokkos_HPX.hpp | 1016 +-- lib/kokkos/core/src/Kokkos_HostSpace.hpp | 245 +- lib/kokkos/core/src/Kokkos_Layout.hpp | 325 +- lib/kokkos/core/src/Kokkos_Macros.hpp | 722 +-- lib/kokkos/core/src/Kokkos_MasterLock.hpp | 20 +- lib/kokkos/core/src/Kokkos_MemoryPool.hpp | 1138 ++-- lib/kokkos/core/src/Kokkos_MemoryTraits.hpp | 99 +- lib/kokkos/core/src/Kokkos_NumericTraits.hpp | 424 +- lib/kokkos/core/src/Kokkos_OpenMP.hpp | 139 +- lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp | 83 +- .../core/src/Kokkos_OpenMPTargetSpace.hpp | 215 +- lib/kokkos/core/src/Kokkos_Pair.hpp | 319 +- lib/kokkos/core/src/Kokkos_Parallel.hpp | 404 +- .../core/src/Kokkos_Parallel_Reduce.hpp | 1143 ++-- .../core/src/Kokkos_PointerOwnership.hpp | 16 +- .../src/Kokkos_Profiling_ProfileSection.hpp | 175 +- lib/kokkos/core/src/Kokkos_Qthreads.hpp | 77 +- lib/kokkos/core/src/Kokkos_ROCm.hpp | 169 +- lib/kokkos/core/src/Kokkos_ROCmSpace.hpp | 617 +- lib/kokkos/core/src/Kokkos_ScratchSpace.hpp | 186 +- lib/kokkos/core/src/Kokkos_Serial.hpp | 1495 +++-- lib/kokkos/core/src/Kokkos_TaskPolicy.hpp | 20 +- lib/kokkos/core/src/Kokkos_TaskScheduler.hpp | 749 +-- .../core/src/Kokkos_TaskScheduler_fwd.hpp | 159 +- lib/kokkos/core/src/Kokkos_Threads.hpp | 117 +- lib/kokkos/core/src/Kokkos_Timer.hpp | 41 +- lib/kokkos/core/src/Kokkos_UniqueToken.hpp | 44 +- lib/kokkos/core/src/Kokkos_Vectorization.hpp | 14 +- lib/kokkos/core/src/Kokkos_View.hpp | 3779 ++++++----- .../core/src/Kokkos_WorkGraphPolicy.hpp | 200 +- lib/kokkos/core/src/Kokkos_hwloc.hpp | 34 +- lib/kokkos/core/src/Makefile | 117 - .../core/src/Makefile.generate_build_files | 125 - .../core/src/Makefile.generate_header_lists | 32 - .../core/src/OpenMP/Kokkos_OpenMP_Exec.cpp | 406 +- .../core/src/OpenMP/Kokkos_OpenMP_Exec.hpp | 326 +- .../src/OpenMP/Kokkos_OpenMP_Parallel.hpp | 1706 +++-- .../core/src/OpenMP/Kokkos_OpenMP_Task.cpp | 80 +- .../core/src/OpenMP/Kokkos_OpenMP_Task.hpp | 306 +- .../core/src/OpenMP/Kokkos_OpenMP_Team.hpp | 404 +- .../OpenMP/Kokkos_OpenMP_ViewCopyETIAvail.hpp | 18 +- .../OpenMP/Kokkos_OpenMP_ViewCopyETIDecl.hpp | 18 +- .../OpenMP/Kokkos_OpenMP_WorkGraphPolicy.hpp | 80 +- .../OpenMPTarget/Kokkos_OpenMPTargetSpace.cpp | 296 +- .../OpenMPTarget/Kokkos_OpenMPTarget_Exec.cpp | 249 +- .../OpenMPTarget/Kokkos_OpenMPTarget_Exec.hpp | 872 +-- .../Kokkos_OpenMPTarget_Parallel.hpp | 1150 ++-- .../OpenMPTarget/Kokkos_OpenMPTarget_Task.cpp | 235 +- .../OpenMPTarget/Kokkos_OpenMPTarget_Task.hpp | 340 +- .../core/src/Qthreads/Kokkos_QthreadsExec.cpp | 454 +- .../core/src/Qthreads/Kokkos_QthreadsExec.hpp | 614 +- .../src/Qthreads/Kokkos_Qthreads_Parallel.hpp | 945 +-- .../src/Qthreads/Kokkos_Qthreads_Task.cpp | 224 +- .../src/Qthreads/Kokkos_Qthreads_Task.hpp | 122 +- .../Kokkos_Qthreads_TaskPolicy.hpp.old | 2 +- .../Qthreads/Kokkos_Qthreads_TaskQueue.hpp | 290 +- .../Kokkos_Qthreads_TaskQueue_impl.hpp | 311 +- .../KokkosExp_ROCm_IterateTile_Refactor.hpp | 3256 +++++----- .../core/src/ROCm/Kokkos_ROCm_Atomic.hpp | 826 +-- .../core/src/ROCm/Kokkos_ROCm_Config.hpp | 11 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Exec.cpp | 76 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Exec.hpp | 212 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Impl.cpp | 748 ++- .../core/src/ROCm/Kokkos_ROCm_Invoke.hpp | 122 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Join.hpp | 32 +- .../core/src/ROCm/Kokkos_ROCm_Parallel.hpp | 2543 ++++---- .../core/src/ROCm/Kokkos_ROCm_Reduce.hpp | 162 +- .../core/src/ROCm/Kokkos_ROCm_ReduceScan.hpp | 501 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Scan.hpp | 329 +- .../core/src/ROCm/Kokkos_ROCm_Space.cpp | 745 ++- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Task.cpp | 118 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Task.hpp | 489 +- lib/kokkos/core/src/ROCm/Kokkos_ROCm_Tile.hpp | 628 +- .../src/ROCm/Kokkos_ROCm_Vectorization.hpp | 512 +- .../src/ROCm/Kokkos_ROCm_ViewCopyETIAvail.hpp | 18 +- .../src/ROCm/Kokkos_ROCm_ViewCopyETIDecl.hpp | 18 +- lib/kokkos/core/src/ROCm/hc_math_std.hpp | 426 +- .../Serial/Kokkos_Serial_ViewCopyETIAvail.hpp | 18 +- .../Serial/Kokkos_Serial_ViewCopyETIDecl.hpp | 18 +- .../core/src/Threads/Kokkos_ThreadsExec.cpp | 828 ++- .../core/src/Threads/Kokkos_ThreadsExec.hpp | 791 +-- .../src/Threads/Kokkos_ThreadsExec_base.cpp | 158 +- .../core/src/Threads/Kokkos_ThreadsTeam.hpp | 1389 ++-- .../src/Threads/Kokkos_Threads_Parallel.hpp | 1412 ++--- .../Kokkos_Threads_ViewCopyETIAvail.hpp | 18 +- .../Kokkos_Threads_ViewCopyETIDecl.hpp | 18 +- .../Kokkos_Threads_WorkGraphPolicy.hpp | 103 +- lib/kokkos/core/src/dummy.cpp | 10 + ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 33 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 33 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 33 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 34 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 35 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 34 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 35 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 33 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 33 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 34 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 33 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 34 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 35 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 34 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 35 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 34 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 35 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 35 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 37 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 37 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 37 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 37 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 37 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 37 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 35 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 34 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 35 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 35 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 34 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 34 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 35 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 34 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 34 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 35 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 37 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 37 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 37 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 37 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 37 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 37 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 37 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 37 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 37 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 37 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 37 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 37 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 37 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 37 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 37 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 37 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 37 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 37 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 37 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 37 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 37 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 36 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 37 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 34 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 35 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 33 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 34 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 35 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 35 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 34 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 34 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 35 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 34 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 34 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 35 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 35 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 33 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 34 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 35 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank1.cpp | 35 +- ...TIInst_int64_t_double_LayoutLeft_Rank2.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank3.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank4.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank5.cpp | 36 +- ...TIInst_int64_t_double_LayoutLeft_Rank8.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank1.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank2.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank3.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank4.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank5.cpp | 36 +- ...IInst_int64_t_double_LayoutRight_Rank8.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank1.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank2.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank3.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank4.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank5.cpp | 36 +- ...Inst_int64_t_double_LayoutStride_Rank8.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank1.cpp | 34 +- ...ETIInst_int64_t_float_LayoutLeft_Rank2.cpp | 35 +- ...ETIInst_int64_t_float_LayoutLeft_Rank3.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank4.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank5.cpp | 36 +- ...ETIInst_int64_t_float_LayoutLeft_Rank8.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank1.cpp | 35 +- ...TIInst_int64_t_float_LayoutRight_Rank2.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank3.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank4.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank5.cpp | 36 +- ...TIInst_int64_t_float_LayoutRight_Rank8.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank1.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank2.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank3.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank4.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank5.cpp | 36 +- ...IInst_int64_t_float_LayoutStride_Rank8.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank1.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank2.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank3.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank4.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...IInst_int64_t_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank1.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank2.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank3.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank4.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank5.cpp | 36 +- ...Inst_int64_t_int64_t_LayoutRight_Rank8.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank1.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank2.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank3.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank4.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank5.cpp | 36 +- ...nst_int64_t_int64_t_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank3.cpp | 34 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank4.cpp | 35 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int64_t_int_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int64_t_int_LayoutRight_Rank2.cpp | 34 +- ...yETIInst_int64_t_int_LayoutRight_Rank3.cpp | 35 +- ...yETIInst_int64_t_int_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int64_t_int_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank1.cpp | 34 +- ...ETIInst_int64_t_int_LayoutStride_Rank2.cpp | 35 +- ...ETIInst_int64_t_int_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int64_t_int_LayoutStride_Rank8.cpp | 36 +- ...opyETIInst_int_double_LayoutLeft_Rank1.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank2.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank3.cpp | 33 +- ...opyETIInst_int_double_LayoutLeft_Rank4.cpp | 34 +- ...opyETIInst_int_double_LayoutLeft_Rank5.cpp | 35 +- ...opyETIInst_int_double_LayoutLeft_Rank8.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank1.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank2.cpp | 33 +- ...pyETIInst_int_double_LayoutRight_Rank3.cpp | 34 +- ...pyETIInst_int_double_LayoutRight_Rank4.cpp | 35 +- ...pyETIInst_int_double_LayoutRight_Rank5.cpp | 36 +- ...pyETIInst_int_double_LayoutRight_Rank8.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank1.cpp | 33 +- ...yETIInst_int_double_LayoutStride_Rank2.cpp | 34 +- ...yETIInst_int_double_LayoutStride_Rank3.cpp | 35 +- ...yETIInst_int_double_LayoutStride_Rank4.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank5.cpp | 36 +- ...yETIInst_int_double_LayoutStride_Rank8.cpp | 36 +- ...CopyETIInst_int_float_LayoutLeft_Rank1.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank2.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank3.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank4.cpp | 33 +- ...CopyETIInst_int_float_LayoutLeft_Rank5.cpp | 34 +- ...CopyETIInst_int_float_LayoutLeft_Rank8.cpp | 36 +- ...opyETIInst_int_float_LayoutRight_Rank1.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank2.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank3.cpp | 33 +- ...opyETIInst_int_float_LayoutRight_Rank4.cpp | 34 +- ...opyETIInst_int_float_LayoutRight_Rank5.cpp | 35 +- ...opyETIInst_int_float_LayoutRight_Rank8.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank1.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank2.cpp | 33 +- ...pyETIInst_int_float_LayoutStride_Rank3.cpp | 34 +- ...pyETIInst_int_float_LayoutStride_Rank4.cpp | 35 +- ...pyETIInst_int_float_LayoutStride_Rank5.cpp | 36 +- ...pyETIInst_int_float_LayoutStride_Rank8.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank1.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank2.cpp | 33 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank3.cpp | 34 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank4.cpp | 35 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank5.cpp | 36 +- ...pyETIInst_int_int64_t_LayoutLeft_Rank8.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank1.cpp | 33 +- ...yETIInst_int_int64_t_LayoutRight_Rank2.cpp | 34 +- ...yETIInst_int_int64_t_LayoutRight_Rank3.cpp | 35 +- ...yETIInst_int_int64_t_LayoutRight_Rank4.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank5.cpp | 36 +- ...yETIInst_int_int64_t_LayoutRight_Rank8.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank1.cpp | 34 +- ...ETIInst_int_int64_t_LayoutStride_Rank2.cpp | 35 +- ...ETIInst_int_int64_t_LayoutStride_Rank3.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank4.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank5.cpp | 36 +- ...ETIInst_int_int64_t_LayoutStride_Rank8.cpp | 36 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank1.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank2.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank3.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank4.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank5.cpp | 33 +- ...ewCopyETIInst_int_int_LayoutLeft_Rank8.cpp | 35 +- ...wCopyETIInst_int_int_LayoutRight_Rank1.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank2.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank3.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank4.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank5.cpp | 33 +- ...wCopyETIInst_int_int_LayoutRight_Rank8.cpp | 36 +- ...CopyETIInst_int_int_LayoutStride_Rank1.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank2.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank3.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank4.cpp | 33 +- ...CopyETIInst_int_int_LayoutStride_Rank5.cpp | 34 +- ...CopyETIInst_int_int_LayoutStride_Rank8.cpp | 36 +- .../Kokkos_ViewFillCopyETIAvail_Macros.hpp | 2016 ++++-- .../Kokkos_ViewFillCopyETIDecl_Macros.hpp | 1728 +++-- lib/kokkos/core/src/impl/CMakeLists.txt | 36 +- .../src/impl/KokkosExp_Host_IterateTile.hpp | 3833 ++++++------ .../core/src/impl/KokkosExp_ViewMapping.hpp | 19 +- .../core/src/impl/Kokkos_AnalyzePolicy.hpp | 309 +- .../core/src/impl/Kokkos_Atomic_Assembly.hpp | 113 +- .../Kokkos_Atomic_Compare_Exchange_Strong.hpp | 496 +- .../Kokkos_Atomic_Compare_Exchange_Weak.hpp | 343 +- .../core/src/impl/Kokkos_Atomic_Decrement.hpp | 122 +- .../core/src/impl/Kokkos_Atomic_Exchange.hpp | 436 +- .../core/src/impl/Kokkos_Atomic_Fetch_Add.hpp | 389 +- .../core/src/impl/Kokkos_Atomic_Fetch_And.hpp | 117 +- .../core/src/impl/Kokkos_Atomic_Fetch_Or.hpp | 117 +- .../core/src/impl/Kokkos_Atomic_Fetch_Sub.hpp | 316 +- .../core/src/impl/Kokkos_Atomic_Generic.hpp | 428 +- .../core/src/impl/Kokkos_Atomic_Increment.hpp | 128 +- .../core/src/impl/Kokkos_Atomic_Load.hpp | 185 +- .../src/impl/Kokkos_Atomic_Memory_Order.hpp | 55 +- .../core/src/impl/Kokkos_Atomic_Store.hpp | 189 +- .../core/src/impl/Kokkos_Atomic_View.hpp | 340 +- .../core/src/impl/Kokkos_Atomic_Windows.hpp | 340 +- lib/kokkos/core/src/impl/Kokkos_BitOps.hpp | 139 +- .../core/src/impl/Kokkos_CPUDiscovery.cpp | 55 +- .../core/src/impl/Kokkos_CPUDiscovery.hpp | 15 +- lib/kokkos/core/src/impl/Kokkos_ChaseLev.hpp | 205 +- lib/kokkos/core/src/impl/Kokkos_ClockTic.hpp | 46 +- .../core/src/impl/Kokkos_ConcurrentBitset.hpp | 338 +- lib/kokkos/core/src/impl/Kokkos_Core.cpp | 940 +-- lib/kokkos/core/src/impl/Kokkos_EBO.hpp | 223 +- lib/kokkos/core/src/impl/Kokkos_Error.cpp | 173 +- lib/kokkos/core/src/impl/Kokkos_Error.hpp | 199 +- .../core/src/impl/Kokkos_ExecPolicy.cpp | 28 +- .../src/impl/Kokkos_FixedBufferMemoryPool.hpp | 142 +- .../core/src/impl/Kokkos_FunctorAdapter.hpp | 3126 ++++----- .../core/src/impl/Kokkos_FunctorAnalysis.hpp | 1203 ++-- lib/kokkos/core/src/impl/Kokkos_HBWSpace.cpp | 328 +- .../core/src/impl/Kokkos_HostBarrier.cpp | 94 +- .../core/src/impl/Kokkos_HostBarrier.hpp | 237 +- lib/kokkos/core/src/impl/Kokkos_HostSpace.cpp | 543 +- .../src/impl/Kokkos_HostSpace_deepcopy.cpp | 101 +- .../src/impl/Kokkos_HostSpace_deepcopy.hpp | 20 +- .../core/src/impl/Kokkos_HostThreadTeam.cpp | 289 +- .../core/src/impl/Kokkos_HostThreadTeam.hpp | 1322 ++-- lib/kokkos/core/src/impl/Kokkos_LIFO.hpp | 171 +- .../core/src/impl/Kokkos_LinkedListNode.hpp | 109 +- .../core/src/impl/Kokkos_MemoryPool.cpp | 95 +- .../src/impl/Kokkos_MemoryPoolAllocator.hpp | 53 +- .../core/src/impl/Kokkos_MemorySpace.hpp | 110 + .../core/src/impl/Kokkos_Memory_Fence.hpp | 69 +- .../src/impl/Kokkos_MultipleTaskQueue.hpp | 515 +- lib/kokkos/core/src/impl/Kokkos_OldMacros.hpp | 70 +- .../core/src/impl/Kokkos_OptionalRef.hpp | 87 +- .../core/src/impl/Kokkos_PhysicalLayout.hpp | 43 +- .../src/impl/Kokkos_Profiling_DeviceInfo.hpp | 85 +- .../src/impl/Kokkos_Profiling_Interface.cpp | 380 +- .../src/impl/Kokkos_Profiling_Interface.hpp | 170 +- lib/kokkos/core/src/impl/Kokkos_Serial.cpp | 167 +- .../core/src/impl/Kokkos_Serial_Task.cpp | 20 +- .../core/src/impl/Kokkos_Serial_Task.hpp | 195 +- .../impl/Kokkos_Serial_WorkGraphPolicy.hpp | 83 +- .../core/src/impl/Kokkos_SharedAlloc.cpp | 388 +- .../core/src/impl/Kokkos_SharedAlloc.hpp | 437 +- .../src/impl/Kokkos_SimpleTaskScheduler.hpp | 574 +- .../core/src/impl/Kokkos_SingleTaskQueue.hpp | 123 +- lib/kokkos/core/src/impl/Kokkos_Spinwait.cpp | 155 +- lib/kokkos/core/src/impl/Kokkos_Spinwait.hpp | 78 +- .../core/src/impl/Kokkos_Stacktrace.cpp | 247 + .../core/src/impl/Kokkos_Stacktrace.hpp | 45 + lib/kokkos/core/src/impl/Kokkos_Tags.hpp | 44 +- lib/kokkos/core/src/impl/Kokkos_TaskBase.hpp | 235 +- lib/kokkos/core/src/impl/Kokkos_TaskNode.hpp | 550 +- .../core/src/impl/Kokkos_TaskPolicyData.hpp | 103 +- lib/kokkos/core/src/impl/Kokkos_TaskQueue.hpp | 151 +- .../core/src/impl/Kokkos_TaskQueueCommon.hpp | 366 +- .../impl/Kokkos_TaskQueueMemoryManager.hpp | 173 +- .../src/impl/Kokkos_TaskQueueMultiple.hpp | 165 +- .../impl/Kokkos_TaskQueueMultiple_impl.hpp | 20 +- .../core/src/impl/Kokkos_TaskQueue_impl.hpp | 443 +- .../core/src/impl/Kokkos_TaskResult.hpp | 101 +- .../core/src/impl/Kokkos_TaskTeamMember.hpp | 43 +- lib/kokkos/core/src/impl/Kokkos_Timer.hpp | 28 +- lib/kokkos/core/src/impl/Kokkos_Traits.hpp | 539 +- lib/kokkos/core/src/impl/Kokkos_Utilities.hpp | 460 +- .../core/src/impl/Kokkos_VLAEmulation.hpp | 164 +- lib/kokkos/core/src/impl/Kokkos_ViewArray.hpp | 882 +-- lib/kokkos/core/src/impl/Kokkos_ViewCtor.hpp | 260 +- .../src/impl/Kokkos_ViewFillCopyETIAvail.hpp | 96 +- .../src/impl/Kokkos_ViewFillCopyETIDecl.hpp | 115 +- .../core/src/impl/Kokkos_ViewLayoutTiled.hpp | 1806 ++++-- .../core/src/impl/Kokkos_ViewMapping.hpp | 5558 +++++++++-------- lib/kokkos/core/src/impl/Kokkos_ViewTile.hpp | 262 +- .../core/src/impl/Kokkos_ViewUniformType.hpp | 116 +- .../core/src/impl/Kokkos_Volatile_Load.hpp | 163 +- lib/kokkos/core/src/impl/Kokkos_hwloc.cpp | 731 +-- lib/kokkos/core/src/kokkos.pc.in | 18 +- lib/kokkos/core/unit_test/CMakeLists.txt | 915 +-- lib/kokkos/core/unit_test/Makefile | 57 +- lib/kokkos/core/unit_test/TestAggregate.hpp | 132 +- lib/kokkos/core/unit_test/TestAtomic.hpp | 431 +- .../core/unit_test/TestAtomicOperations.hpp | 728 +-- .../TestAtomicOperations_complexdouble.hpp | 33 +- .../TestAtomicOperations_complexfloat.hpp | 33 +- .../unit_test/TestAtomicOperations_double.hpp | 37 +- .../unit_test/TestAtomicOperations_float.hpp | 37 +- .../unit_test/TestAtomicOperations_int.hpp | 58 +- .../TestAtomicOperations_longint.hpp | 58 +- .../TestAtomicOperations_longlongint.hpp | 58 +- .../TestAtomicOperations_unsignedint.hpp | 58 +- .../TestAtomicOperations_unsignedlongint.hpp | 58 +- lib/kokkos/core/unit_test/TestAtomicViews.hpp | 1529 ++--- lib/kokkos/core/unit_test/TestCXX11.hpp | 399 +- .../core/unit_test/TestCXX11Deduction.hpp | 65 +- .../core/unit_test/TestCompilerMacros.hpp | 74 +- lib/kokkos/core/unit_test/TestComplex.hpp | 364 +- .../core/unit_test/TestConcurrentBitset.hpp | 156 +- lib/kokkos/core/unit_test/TestCrs.hpp | 163 +- lib/kokkos/core/unit_test/TestDeepCopy.hpp | 223 +- .../unit_test/TestDefaultDeviceTypeInit.hpp | 380 +- .../core/unit_test/TestFunctorAnalysis.hpp | 171 +- lib/kokkos/core/unit_test/TestHWLOC.cpp | 25 +- lib/kokkos/core/unit_test/TestHostBarrier.cpp | 13 +- lib/kokkos/core/unit_test/TestInit.hpp | 35 +- .../core/unit_test/TestLocalDeepCopy.hpp | 1541 ++--- lib/kokkos/core/unit_test/TestMDRange.hpp | 3629 ++++++----- lib/kokkos/core/unit_test/TestMDRange_a.hpp | 24 +- lib/kokkos/core/unit_test/TestMDRange_b.hpp | 24 +- lib/kokkos/core/unit_test/TestMDRange_c.hpp | 30 +- lib/kokkos/core/unit_test/TestMDRange_d.hpp | 40 +- lib/kokkos/core/unit_test/TestMDRange_e.hpp | 24 +- lib/kokkos/core/unit_test/TestMemoryPool.hpp | 679 +- .../core/unit_test/TestPolicyConstruction.hpp | 1299 ++-- lib/kokkos/core/unit_test/TestRange.hpp | 412 +- lib/kokkos/core/unit_test/TestReduce.hpp | 465 +- .../unit_test/TestReduceCombinatorical.hpp | 599 +- .../core/unit_test/TestReduceDeviceView.hpp | 194 +- lib/kokkos/core/unit_test/TestReducers.hpp | 925 +-- lib/kokkos/core/unit_test/TestReducers_a.hpp | 18 +- lib/kokkos/core/unit_test/TestReducers_b.hpp | 18 +- lib/kokkos/core/unit_test/TestReducers_c.hpp | 18 +- lib/kokkos/core/unit_test/TestReducers_d.hpp | 19 +- lib/kokkos/core/unit_test/TestResize.hpp | 397 +- lib/kokkos/core/unit_test/TestScan.hpp | 114 +- lib/kokkos/core/unit_test/TestSharedAlloc.hpp | 154 +- .../unit_test/TestStackTrace.cpp} | 42 +- lib/kokkos/core/unit_test/TestStackTrace.hpp | 169 + .../unit_test/TestStackTrace_f0.cpp} | 45 +- .../unit_test/TestStackTrace_f1.cpp} | 45 +- .../unit_test/TestStackTrace_f2.cpp} | 49 +- .../core/unit_test/TestStackTrace_f3.cpp | 62 + .../core/unit_test/TestStackTrace_f4.cpp | 53 + .../core/unit_test/TestTaskScheduler.hpp | 910 ++- .../unit_test/TestTaskScheduler_single.hpp | 62 +- lib/kokkos/core/unit_test/TestTeam.hpp | 1237 ++-- .../core/unit_test/TestTeamTeamSize.hpp | 243 +- lib/kokkos/core/unit_test/TestTeamVector.hpp | 1037 +-- .../core/unit_test/TestTeamVectorRange.hpp | 421 +- .../unit_test/TestTemplateMetaFunctions.hpp | 169 +- lib/kokkos/core/unit_test/TestTile.hpp | 149 +- lib/kokkos/core/unit_test/TestUniqueToken.hpp | 120 +- lib/kokkos/core/unit_test/TestUtilities.hpp | 455 +- lib/kokkos/core/unit_test/TestViewAPI.hpp | 1899 +++--- lib/kokkos/core/unit_test/TestViewAPI_a.hpp | 20 +- lib/kokkos/core/unit_test/TestViewAPI_b.hpp | 24 +- lib/kokkos/core/unit_test/TestViewAPI_c.hpp | 22 +- lib/kokkos/core/unit_test/TestViewAPI_d.hpp | 30 +- lib/kokkos/core/unit_test/TestViewAPI_e.hpp | 212 +- lib/kokkos/core/unit_test/TestViewCopy.hpp | 202 +- .../unit_test/TestViewCtorPropEmbeddedDim.hpp | 121 +- .../TestViewLayoutStrideAssignment.hpp | 1092 ++-- .../core/unit_test/TestViewLayoutTiled.hpp | 2157 ++++--- .../core/unit_test/TestViewMapping_a.hpp | 1711 ++--- .../core/unit_test/TestViewMapping_b.hpp | 241 +- .../unit_test/TestViewMapping_subview.hpp | 259 +- lib/kokkos/core/unit_test/TestViewOfClass.hpp | 91 +- lib/kokkos/core/unit_test/TestViewResize.hpp | 58 + .../core/unit_test/TestViewSpaceAssign.hpp | 42 +- lib/kokkos/core/unit_test/TestViewSubview.hpp | 2511 +++++--- lib/kokkos/core/unit_test/TestView_64bit.hpp | 119 +- lib/kokkos/core/unit_test/TestWorkGraph.hpp | 99 +- lib/kokkos/core/unit_test/UnitTestMain.cpp | 15 +- .../core/unit_test/UnitTestMainInit.cpp | 19 +- .../unit_test/UnitTest_PushFinalizeHook.cpp | 67 +- .../UnitTest_PushFinalizeHook_terminate.cpp | 33 +- .../unit_test/config/cmaketest/CMakeLists.txt | 1 - .../configuration/test-code/CMakeLists.txt | 44 + .../configuration/test-code/Makefile | 46 + .../configuration/test-code/main.cpp | 6 + .../configuration/test-code/test_config.bash | 7 + .../test-code/test_config_arch_list.bash | 45 + .../test-code/test_config_device_list.bash | 45 + .../test-code/test_config_options_list.bash | 49 + .../test-code/test_config_run.bash | 111 + .../cuda/TestCudaHostPinned_Category.hpp | 28 +- .../cuda/TestCudaHostPinned_SharedAlloc.cpp | 19 +- .../cuda/TestCudaHostPinned_ViewAPI_a.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_b.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_c.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_d.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewAPI_e.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewCopy.cpp | 11 +- .../cuda/TestCudaHostPinned_ViewMapping_a.cpp | 12 +- .../cuda/TestCudaHostPinned_ViewMapping_b.cpp | 12 +- ...TestCudaHostPinned_ViewMapping_subview.cpp | 12 +- .../unit_test/cuda/TestCudaUVM_Category.hpp | 25 +- .../cuda/TestCudaUVM_SharedAlloc.cpp | 19 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_a.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_b.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_c.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_d.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewAPI_e.cpp | 11 +- .../unit_test/cuda/TestCudaUVM_ViewCopy.cpp | 11 +- .../cuda/TestCudaUVM_ViewMapping_a.cpp | 12 +- .../cuda/TestCudaUVM_ViewMapping_b.cpp | 12 +- .../cuda/TestCudaUVM_ViewMapping_subview.cpp | 12 +- ...estCuda_AtomicOperations_complexdouble.cpp | 16 +- ...TestCuda_AtomicOperations_complexfloat.cpp | 16 +- .../cuda/TestCuda_AtomicOperations_double.cpp | 16 +- .../cuda/TestCuda_AtomicOperations_float.cpp | 16 +- .../cuda/TestCuda_AtomicOperations_int.cpp | 16 +- .../TestCuda_AtomicOperations_longint.cpp | 16 +- .../TestCuda_AtomicOperations_longlongint.cpp | 16 +- .../TestCuda_AtomicOperations_unsignedint.cpp | 16 +- ...tCuda_AtomicOperations_unsignedlongint.cpp | 16 +- .../unit_test/cuda/TestCuda_AtomicViews.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Atomics.cpp | 12 +- .../core/unit_test/cuda/TestCuda_Category.hpp | 25 +- .../core/unit_test/cuda/TestCuda_Complex.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Crs.cpp | 11 +- .../cuda/TestCuda_DebugPinUVMSpace.cpp | 131 + .../cuda/TestCuda_DebugSerialExecution.cpp | 197 + .../cuda/TestCuda_DeepCopyAlignment.cpp | 14 +- .../cuda/TestCuda_FunctorAnalysis.cpp | 47 + .../core/unit_test/cuda/TestCuda_Init.cpp | 21 +- .../unit_test/cuda/TestCuda_InterOp_Init.cpp | 50 +- .../cuda/TestCuda_InterOp_Streams.cpp | 256 +- .../unit_test/cuda/TestCuda_LocalDeepCopy.cpp | 12 +- .../unit_test/cuda/TestCuda_MDRange_a.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_b.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_c.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_d.cpp | 16 +- .../unit_test/cuda/TestCuda_MDRange_e.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Other.cpp | 27 +- .../unit_test/cuda/TestCuda_RangePolicy.cpp | 16 +- .../unit_test/cuda/TestCuda_Reducers_a.cpp | 11 +- .../unit_test/cuda/TestCuda_Reducers_b.cpp | 11 +- .../unit_test/cuda/TestCuda_Reducers_c.cpp | 11 +- .../unit_test/cuda/TestCuda_Reducers_d.cpp | 11 +- .../unit_test/cuda/TestCuda_Reductions.cpp | 11 +- .../cuda/TestCuda_Reductions_DeviceView.cpp | 11 +- .../core/unit_test/cuda/TestCuda_Scan.cpp | 16 +- .../unit_test/cuda/TestCuda_SharedAlloc.cpp | 19 +- .../core/unit_test/cuda/TestCuda_Spaces.cpp | 365 +- .../unit_test/cuda/TestCuda_SubView_a.cpp | 77 +- .../unit_test/cuda/TestCuda_SubView_b.cpp | 35 +- .../unit_test/cuda/TestCuda_SubView_c01.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c02.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c03.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c04.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c05.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c06.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c07.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c08.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c09.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c10.cpp | 18 +- .../unit_test/cuda/TestCuda_SubView_c11.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c12.cpp | 19 +- .../unit_test/cuda/TestCuda_SubView_c13.cpp | 18 +- .../core/unit_test/cuda/TestCuda_Task.cpp | 16 +- .../core/unit_test/cuda/TestCuda_Team.cpp | 85 +- .../cuda/TestCuda_TeamReductionScan.cpp | 63 +- .../unit_test/cuda/TestCuda_TeamScratch.cpp | 59 +- .../unit_test/cuda/TestCuda_TeamTeamSize.cpp | 11 +- .../cuda/TestCuda_TeamVectorRange.cpp | 17 +- .../unit_test/cuda/TestCuda_UniqueToken.cpp | 16 +- .../unit_test/cuda/TestCuda_ViewAPI_a.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_b.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_c.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_d.cpp | 11 +- .../unit_test/cuda/TestCuda_ViewAPI_e.cpp | 11 +- .../TestCuda_ViewLayoutStrideAssignment.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewMapping_a.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewMapping_b.cpp | 12 +- .../cuda/TestCuda_ViewMapping_subview.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewOfClass.cpp | 12 +- .../unit_test/cuda/TestCuda_ViewResize.cpp | 46 + .../unit_test/cuda/TestCuda_View_64bit.cpp | 11 +- .../unit_test/cuda/TestCuda_WorkGraph.cpp | 15 +- .../default/TestDefaultDeviceType.cpp | 39 +- .../default/TestDefaultDeviceTypeInit_1.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_10.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_11.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_12.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_13.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_14.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_15.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_16.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_2.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_3.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_4.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_5.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_6.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_7.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_8.cpp | 2 +- .../default/TestDefaultDeviceTypeInit_9.cpp | 2 +- .../default/TestDefaultDeviceTypeResize.cpp | 18 +- .../TestDefaultDeviceType_Category.hpp | 27 +- .../default/TestDefaultDeviceType_a1.cpp | 19 +- .../default/TestDefaultDeviceType_a2.cpp | 19 +- .../default/TestDefaultDeviceType_a3.cpp | 19 +- .../default/TestDefaultDeviceType_b1.cpp | 18 +- .../default/TestDefaultDeviceType_b2.cpp | 18 +- .../default/TestDefaultDeviceType_b3.cpp | 18 +- .../default/TestDefaultDeviceType_c1.cpp | 20 +- .../default/TestDefaultDeviceType_c2.cpp | 20 +- .../default/TestDefaultDeviceType_c3.cpp | 20 +- .../default/TestDefaultDeviceType_d.cpp | 35 +- ...TestHPX_AtomicOperations_complexdouble.cpp | 46 + .../TestHPX_AtomicOperations_complexfloat.cpp | 46 + .../hpx/TestHPX_AtomicOperations_double.cpp | 16 +- .../hpx/TestHPX_AtomicOperations_float.cpp | 16 +- .../hpx/TestHPX_AtomicOperations_int.cpp | 16 +- .../hpx/TestHPX_AtomicOperations_longint.cpp | 16 +- .../TestHPX_AtomicOperations_longlongint.cpp | 16 +- .../TestHPX_AtomicOperations_unsignedint.cpp | 16 +- ...stHPX_AtomicOperations_unsignedlongint.cpp | 16 +- .../unit_test/hpx/TestHPX_AtomicViews.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Atomics.cpp | 12 +- .../core/unit_test/hpx/TestHPX_Category.hpp | 25 +- .../core/unit_test/hpx/TestHPX_Complex.cpp | 16 +- lib/kokkos/core/unit_test/hpx/TestHPX_Crs.cpp | 11 +- .../hpx/TestHPX_DeepCopyAlignment.cpp | 46 + .../unit_test/hpx/TestHPX_FunctorAnalysis.cpp | 47 + .../core/unit_test/hpx/TestHPX_Init.cpp | 21 +- .../core/unit_test/hpx/TestHPX_InterOp.cpp | 21 +- .../unit_test/hpx/TestHPX_LocalDeepCopy.cpp | 46 + .../core/unit_test/hpx/TestHPX_MDRange_a.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_b.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_c.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_d.cpp | 16 +- .../core/unit_test/hpx/TestHPX_MDRange_e.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Other.cpp | 11 +- .../unit_test/hpx/TestHPX_RangePolicy.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Reducers_a.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reducers_b.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reducers_c.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reducers_d.cpp | 11 +- .../core/unit_test/hpx/TestHPX_Reductions.cpp | 11 +- .../hpx/TestHPX_Reductions_DeviceView.cpp | 46 + .../core/unit_test/hpx/TestHPX_Scan.cpp | 16 +- .../unit_test/hpx/TestHPX_SharedAlloc.cpp | 19 +- .../core/unit_test/hpx/TestHPX_SubView_a.cpp | 68 +- .../core/unit_test/hpx/TestHPX_SubView_b.cpp | 35 +- .../unit_test/hpx/TestHPX_SubView_c01.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c02.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c03.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c04.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c05.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c06.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c07.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c08.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c09.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c10.cpp | 18 +- .../unit_test/hpx/TestHPX_SubView_c11.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c12.cpp | 19 +- .../unit_test/hpx/TestHPX_SubView_c13.cpp | 18 +- .../core/unit_test/hpx/TestHPX_Task.cpp | 16 +- .../core/unit_test/hpx/TestHPX_Team.cpp | 58 +- .../hpx/TestHPX_TeamReductionScan.cpp | 64 +- .../unit_test/hpx/TestHPX_TeamScratch.cpp | 55 +- .../unit_test/hpx/TestHPX_TeamTeamSize.cpp | 46 + .../unit_test/hpx/TestHPX_TeamVectorRange.cpp | 17 +- .../unit_test/hpx/TestHPX_UniqueToken.cpp | 16 +- .../core/unit_test/hpx/TestHPX_ViewAPI_a.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_b.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_c.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_d.cpp | 11 +- .../core/unit_test/hpx/TestHPX_ViewAPI_e.cpp | 11 +- .../TestHPX_ViewLayoutStrideAssignment.cpp | 46 + .../unit_test/hpx/TestHPX_ViewMapping_a.cpp | 12 +- .../unit_test/hpx/TestHPX_ViewMapping_b.cpp | 12 +- .../hpx/TestHPX_ViewMapping_subview.cpp | 12 +- .../unit_test/hpx/TestHPX_ViewOfClass.cpp | 12 +- .../core/unit_test/hpx/TestHPX_ViewResize.cpp | 46 + .../core/unit_test/hpx/TestHPX_View_64bit.cpp | 11 +- .../core/unit_test/hpx/TestHPX_WorkGraph.cpp | 15 +- .../core/unit_test/openmp/TestOpenMP.hpp | 33 +- ...tOpenMP_AtomicOperations_complexdouble.cpp | 16 +- ...stOpenMP_AtomicOperations_complexfloat.cpp | 16 +- .../TestOpenMP_AtomicOperations_double.cpp | 16 +- .../TestOpenMP_AtomicOperations_float.cpp | 16 +- .../TestOpenMP_AtomicOperations_int.cpp | 16 +- .../TestOpenMP_AtomicOperations_longint.cpp | 16 +- ...estOpenMP_AtomicOperations_longlongint.cpp | 16 +- ...estOpenMP_AtomicOperations_unsignedint.cpp | 16 +- ...penMP_AtomicOperations_unsignedlongint.cpp | 16 +- .../openmp/TestOpenMP_AtomicViews.cpp | 16 +- .../unit_test/openmp/TestOpenMP_Atomics.cpp | 12 +- .../unit_test/openmp/TestOpenMP_Category.hpp | 25 +- .../unit_test/openmp/TestOpenMP_Complex.cpp | 16 +- .../core/unit_test/openmp/TestOpenMP_Crs.cpp | 11 +- .../openmp/TestOpenMP_DeepCopyAlignment.cpp | 11 +- .../openmp/TestOpenMP_FunctorAnalysis.cpp | 47 + .../core/unit_test/openmp/TestOpenMP_Init.cpp | 21 +- .../unit_test/openmp/TestOpenMP_InterOp.cpp | 45 +- .../openmp/TestOpenMP_LocalDeepCopy.cpp | 12 +- .../unit_test/openmp/TestOpenMP_MDRange_a.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_b.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_c.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_d.cpp | 16 +- .../unit_test/openmp/TestOpenMP_MDRange_e.cpp | 16 +- .../unit_test/openmp/TestOpenMP_Other.cpp | 119 +- .../openmp/TestOpenMP_RangePolicy.cpp | 16 +- .../openmp/TestOpenMP_Reducers_a.cpp | 11 +- .../openmp/TestOpenMP_Reducers_b.cpp | 11 +- .../openmp/TestOpenMP_Reducers_c.cpp | 11 +- .../openmp/TestOpenMP_Reducers_d.cpp | 11 +- .../openmp/TestOpenMP_Reductions.cpp | 11 +- .../TestOpenMP_Reductions_DeviceView.cpp | 11 +- .../core/unit_test/openmp/TestOpenMP_Scan.cpp | 16 +- .../openmp/TestOpenMP_SharedAlloc.cpp | 19 +- .../unit_test/openmp/TestOpenMP_SubView_a.cpp | 77 +- .../unit_test/openmp/TestOpenMP_SubView_b.cpp | 35 +- .../openmp/TestOpenMP_SubView_c01.cpp | 18 +- .../openmp/TestOpenMP_SubView_c02.cpp | 19 +- .../openmp/TestOpenMP_SubView_c03.cpp | 19 +- .../openmp/TestOpenMP_SubView_c04.cpp | 18 +- .../openmp/TestOpenMP_SubView_c05.cpp | 19 +- .../openmp/TestOpenMP_SubView_c06.cpp | 19 +- .../openmp/TestOpenMP_SubView_c07.cpp | 18 +- .../openmp/TestOpenMP_SubView_c08.cpp | 19 +- .../openmp/TestOpenMP_SubView_c09.cpp | 19 +- .../openmp/TestOpenMP_SubView_c10.cpp | 18 +- .../openmp/TestOpenMP_SubView_c11.cpp | 19 +- .../openmp/TestOpenMP_SubView_c12.cpp | 19 +- .../openmp/TestOpenMP_SubView_c13.cpp | 18 +- .../core/unit_test/openmp/TestOpenMP_Task.cpp | 16 +- .../core/unit_test/openmp/TestOpenMP_Team.cpp | 85 +- .../openmp/TestOpenMP_TeamReductionScan.cpp | 64 +- .../openmp/TestOpenMP_TeamScratch.cpp | 59 +- .../openmp/TestOpenMP_TeamTeamSize.cpp | 12 +- .../openmp/TestOpenMP_TeamVectorRange.cpp | 17 +- .../openmp/TestOpenMP_UniqueToken.cpp | 16 +- .../unit_test/openmp/TestOpenMP_ViewAPI_a.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_b.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_c.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_d.cpp | 11 +- .../unit_test/openmp/TestOpenMP_ViewAPI_e.cpp | 11 +- .../TestOpenMP_ViewLayoutStrideAssignment.cpp | 12 +- .../openmp/TestOpenMP_ViewMapping_a.cpp | 12 +- .../openmp/TestOpenMP_ViewMapping_b.cpp | 12 +- .../openmp/TestOpenMP_ViewMapping_subview.cpp | 12 +- .../openmp/TestOpenMP_ViewOfClass.cpp | 12 +- .../openmp/TestOpenMP_ViewResize.cpp | 46 + .../openmp/TestOpenMP_View_64bit.cpp | 11 +- .../unit_test/openmp/TestOpenMP_WorkGraph.cpp | 15 +- .../openmptarget/TestOpenMPTarget.hpp | 41 +- ...PTarget_AtomicOperations_complexdouble.cpp | 16 +- ...MPTarget_AtomicOperations_complexfloat.cpp | 16 +- ...stOpenMPTarget_AtomicOperations_double.cpp | 16 +- ...estOpenMPTarget_AtomicOperations_float.cpp | 16 +- .../TestOpenMPTarget_AtomicOperations_int.cpp | 16 +- ...tOpenMPTarget_AtomicOperations_longint.cpp | 16 +- ...nMPTarget_AtomicOperations_longlongint.cpp | 16 +- ...nMPTarget_AtomicOperations_unsignedint.cpp | 16 +- ...arget_AtomicOperations_unsignedlongint.cpp | 16 +- .../TestOpenMPTarget_AtomicViews.cpp | 16 +- .../openmptarget/TestOpenMPTarget_Atomics.cpp | 12 +- .../TestOpenMPTarget_Category.hpp | 25 +- .../openmptarget/TestOpenMPTarget_Complex.cpp | 16 +- .../TestOpenMPTarget_DeepCopyAlignment.cpp | 11 +- .../openmptarget/TestOpenMPTarget_Init.cpp | 21 +- .../TestOpenMPTarget_MDRange_a.cpp | 16 +- .../TestOpenMPTarget_MDRange_b.cpp | 16 +- .../TestOpenMPTarget_MDRange_c.cpp | 16 +- .../TestOpenMPTarget_MDRange_d.cpp | 16 +- .../TestOpenMPTarget_MDRange_e.cpp | 16 +- .../openmptarget/TestOpenMPTarget_Other.cpp | 23 +- .../TestOpenMPTarget_RangePolicy.cpp | 16 +- .../TestOpenMPTarget_Reducers_a.cpp | 11 +- .../TestOpenMPTarget_Reducers_b.cpp | 11 +- .../TestOpenMPTarget_Reducers_c.cpp | 11 +- .../TestOpenMPTarget_Reducers_d.cpp | 11 +- .../TestOpenMPTarget_Reductions.cpp | 11 +- .../openmptarget/TestOpenMPTarget_Scan.cpp | 16 +- .../TestOpenMPTarget_SharedAlloc.cpp | 20 +- .../TestOpenMPTarget_SubView_a.cpp | 77 +- .../TestOpenMPTarget_SubView_b.cpp | 35 +- .../TestOpenMPTarget_SubView_c01.cpp | 18 +- .../TestOpenMPTarget_SubView_c02.cpp | 19 +- .../TestOpenMPTarget_SubView_c03.cpp | 19 +- .../TestOpenMPTarget_SubView_c04.cpp | 18 +- .../TestOpenMPTarget_SubView_c05.cpp | 19 +- .../TestOpenMPTarget_SubView_c06.cpp | 19 +- .../TestOpenMPTarget_SubView_c07.cpp | 18 +- .../TestOpenMPTarget_SubView_c08.cpp | 19 +- .../TestOpenMPTarget_SubView_c09.cpp | 19 +- .../TestOpenMPTarget_SubView_c10.cpp | 18 +- .../TestOpenMPTarget_SubView_c11.cpp | 19 +- .../TestOpenMPTarget_SubView_c12.cpp | 19 +- .../openmptarget/TestOpenMPTarget_Team.cpp | 58 +- .../TestOpenMPTarget_TeamReductionScan.cpp | 64 +- .../TestOpenMPTarget_TeamScratch.cpp | 55 +- .../TestOpenMPTarget_ViewAPI_a.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_b.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_c.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_d.cpp | 11 +- .../TestOpenMPTarget_ViewAPI_e.cpp | 11 +- .../TestOpenMPTarget_ViewMapping_a.cpp | 12 +- .../TestOpenMPTarget_ViewMapping_b.cpp | 12 +- .../TestOpenMPTarget_ViewMapping_subview.cpp | 12 +- .../TestOpenMPTarget_ViewOfClass.cpp | 12 +- ...threads_AtomicOperations_complexdouble.cpp | 16 +- ...qthreads_AtomicOperations_complexfloat.cpp | 16 +- .../TestQqthreads_AtomicOperations_double.cpp | 16 +- .../TestQqthreads_AtomicOperations_float.cpp | 16 +- .../TestQqthreads_AtomicOperations_int.cpp | 16 +- ...TestQqthreads_AtomicOperations_longint.cpp | 16 +- ...Qqthreads_AtomicOperations_longlongint.cpp | 16 +- ...Qqthreads_AtomicOperations_unsignedint.cpp | 16 +- ...reads_AtomicOperations_unsignedlongint.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_a.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_b.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_c.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_d.cpp | 16 +- .../qthreads/TestQqthreads_MDRange_e.cpp | 16 +- .../qthreads/TestQqthreads_ViewAPI_a.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_b.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_c.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_d.cpp | 11 +- .../qthreads/TestQqthreads_ViewAPI_e.cpp | 11 +- .../core/unit_test/qthreads/TestQthreads.hpp | 42 +- .../qthreads/TestQthreads_Atomics.cpp | 28 +- .../qthreads/TestQthreads_Category.hpp | 25 +- .../qthreads/TestQthreads_Complex.cpp | 5 +- .../TestQthreads_DeepCopyAlignment.cpp | 11 +- .../unit_test/qthreads/TestQthreads_Other.cpp | 57 +- .../qthreads/TestQthreads_Reductions.cpp | 49 +- .../qthreads/TestQthreads_SubView_a.cpp | 46 +- .../qthreads/TestQthreads_SubView_b.cpp | 19 +- .../qthreads/TestQthreads_SubView_c01.cpp | 16 +- .../qthreads/TestQthreads_SubView_c02.cpp | 16 +- .../qthreads/TestQthreads_SubView_c03.cpp | 16 +- .../qthreads/TestQthreads_SubView_c04.cpp | 16 +- .../qthreads/TestQthreads_SubView_c05.cpp | 16 +- .../qthreads/TestQthreads_SubView_c06.cpp | 16 +- .../qthreads/TestQthreads_SubView_c07.cpp | 16 +- .../qthreads/TestQthreads_SubView_c08.cpp | 16 +- .../qthreads/TestQthreads_SubView_c09.cpp | 16 +- .../qthreads/TestQthreads_SubView_c10.cpp | 16 +- .../qthreads/TestQthreads_SubView_c11.cpp | 16 +- .../qthreads/TestQthreads_SubView_c12.cpp | 16 +- .../qthreads/TestQthreads_SubView_c13.cpp | 16 +- .../unit_test/qthreads/TestQthreads_Team.cpp | 41 +- .../qthreads/TestQthreads_ViewAPI_a.cpp | 16 +- .../qthreads/TestQthreads_ViewAPI_b.cpp | 34 +- .../rocm/TestROCmHostPinned_Category.hpp | 25 +- .../rocm/TestROCmHostPinned_SharedAlloc.cpp | 19 +- .../rocm/TestROCmHostPinned_ViewAPI_a.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_b.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_c.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_d.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewAPI_e.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewCopy.cpp | 11 +- .../rocm/TestROCmHostPinned_ViewMapping_a.cpp | 12 +- .../rocm/TestROCmHostPinned_ViewMapping_b.cpp | 12 +- ...TestROCmHostPinned_ViewMapping_subview.cpp | 12 +- .../rocm/TestROCmHostPinned_View_64bit.cpp | 11 +- .../rocm/TestROCm_AtomicOperations_double.cpp | 16 +- .../rocm/TestROCm_AtomicOperations_float.cpp | 16 +- .../rocm/TestROCm_AtomicOperations_int.cpp | 16 +- .../TestROCm_AtomicOperations_longint.cpp | 16 +- .../TestROCm_AtomicOperations_longlongint.cpp | 16 +- .../TestROCm_AtomicOperations_unsignedint.cpp | 16 +- ...tROCm_AtomicOperations_unsignedlongint.cpp | 16 +- .../unit_test/rocm/TestROCm_AtomicViews.cpp | 16 +- .../core/unit_test/rocm/TestROCm_Atomics.cpp | 12 +- .../core/unit_test/rocm/TestROCm_Category.hpp | 25 +- .../core/unit_test/rocm/TestROCm_Complex.cpp | 16 +- .../core/unit_test/rocm/TestROCm_Crs.cpp | 16 +- .../rocm/TestROCm_DeepCopyAlignment.cpp | 11 +- .../core/unit_test/rocm/TestROCm_Init.cpp | 21 +- .../rocm/TestROCm_MDRangeReduce_a.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_b.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_c.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_d.cpp | 22 +- .../rocm/TestROCm_MDRangeReduce_e.cpp | 22 +- .../unit_test/rocm/TestROCm_MDRange_a.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_b.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_c.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_d.cpp | 16 +- .../unit_test/rocm/TestROCm_MDRange_e.cpp | 16 +- .../core/unit_test/rocm/TestROCm_Other.cpp | 25 +- .../unit_test/rocm/TestROCm_RangePolicy.cpp | 16 +- .../unit_test/rocm/TestROCm_Reducers_a.cpp | 11 +- .../unit_test/rocm/TestROCm_Reducers_b.cpp | 11 +- .../unit_test/rocm/TestROCm_Reducers_c.cpp | 11 +- .../unit_test/rocm/TestROCm_Reducers_d.cpp | 11 +- .../unit_test/rocm/TestROCm_Reductions.cpp | 11 +- .../core/unit_test/rocm/TestROCm_Scan.cpp | 16 +- .../unit_test/rocm/TestROCm_SharedAlloc.cpp | 20 +- .../core/unit_test/rocm/TestROCm_Spaces.cpp | 205 +- .../unit_test/rocm/TestROCm_SubView_a.cpp | 77 +- .../unit_test/rocm/TestROCm_SubView_b.cpp | 35 +- .../unit_test/rocm/TestROCm_SubView_c01.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c02.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c03.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c04.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c05.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c06.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c07.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c08.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c09.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c10.cpp | 18 +- .../unit_test/rocm/TestROCm_SubView_c11.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c12.cpp | 19 +- .../unit_test/rocm/TestROCm_SubView_c13.cpp | 18 +- .../core/unit_test/rocm/TestROCm_Team.cpp | 58 +- .../rocm/TestROCm_TeamReductionScan.cpp | 63 +- .../unit_test/rocm/TestROCm_TeamScratch.cpp | 59 +- .../unit_test/rocm/TestROCm_TeamTeamSize.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_a.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_b.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_c.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_d.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewAPI_e.cpp | 11 +- .../unit_test/rocm/TestROCm_ViewMapping_a.cpp | 12 +- .../unit_test/rocm/TestROCm_ViewMapping_b.cpp | 12 +- .../rocm/TestROCm_ViewMapping_subview.cpp | 12 +- .../unit_test/rocm/TestROCm_ViewOfClass.cpp | 12 +- ...tSerial_AtomicOperations_complexdouble.cpp | 16 +- ...stSerial_AtomicOperations_complexfloat.cpp | 16 +- .../TestSerial_AtomicOperations_double.cpp | 16 +- .../TestSerial_AtomicOperations_float.cpp | 16 +- .../TestSerial_AtomicOperations_int.cpp | 16 +- .../TestSerial_AtomicOperations_longint.cpp | 16 +- ...estSerial_AtomicOperations_longlongint.cpp | 16 +- ...estSerial_AtomicOperations_unsignedint.cpp | 16 +- ...erial_AtomicOperations_unsignedlongint.cpp | 16 +- .../serial/TestSerial_AtomicViews.cpp | 16 +- .../unit_test/serial/TestSerial_Atomics.cpp | 12 +- .../unit_test/serial/TestSerial_Category.hpp | 25 +- .../unit_test/serial/TestSerial_Complex.cpp | 16 +- .../core/unit_test/serial/TestSerial_Crs.cpp | 11 +- .../serial/TestSerial_DeepCopyAlignment.cpp | 11 +- .../serial/TestSerial_FunctorAnalysis.cpp | 47 + .../core/unit_test/serial/TestSerial_Init.cpp | 21 +- .../serial/TestSerial_LocalDeepCopy.cpp | 12 +- .../unit_test/serial/TestSerial_MDRange_a.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_b.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_c.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_d.cpp | 16 +- .../unit_test/serial/TestSerial_MDRange_e.cpp | 16 +- .../unit_test/serial/TestSerial_Other.cpp | 27 +- .../serial/TestSerial_RangePolicy.cpp | 16 +- .../serial/TestSerial_Reducers_a.cpp | 11 +- .../serial/TestSerial_Reducers_b.cpp | 11 +- .../serial/TestSerial_Reducers_c.cpp | 11 +- .../serial/TestSerial_Reducers_d.cpp | 11 +- .../serial/TestSerial_Reductions.cpp | 11 +- .../TestSerial_Reductions_DeviceView.cpp | 11 +- .../core/unit_test/serial/TestSerial_Scan.cpp | 16 +- .../serial/TestSerial_SharedAlloc.cpp | 19 +- .../unit_test/serial/TestSerial_SubView_a.cpp | 77 +- .../unit_test/serial/TestSerial_SubView_b.cpp | 35 +- .../serial/TestSerial_SubView_c01.cpp | 18 +- .../serial/TestSerial_SubView_c02.cpp | 19 +- .../serial/TestSerial_SubView_c03.cpp | 19 +- .../serial/TestSerial_SubView_c04.cpp | 18 +- .../serial/TestSerial_SubView_c05.cpp | 19 +- .../serial/TestSerial_SubView_c06.cpp | 19 +- .../serial/TestSerial_SubView_c07.cpp | 18 +- .../serial/TestSerial_SubView_c08.cpp | 19 +- .../serial/TestSerial_SubView_c09.cpp | 19 +- .../serial/TestSerial_SubView_c10.cpp | 18 +- .../serial/TestSerial_SubView_c11.cpp | 19 +- .../serial/TestSerial_SubView_c12.cpp | 19 +- .../serial/TestSerial_SubView_c13.cpp | 18 +- .../core/unit_test/serial/TestSerial_Task.cpp | 16 +- .../core/unit_test/serial/TestSerial_Team.cpp | 85 +- .../serial/TestSerial_TeamReductionScan.cpp | 64 +- .../serial/TestSerial_TeamScratch.cpp | 59 +- .../serial/TestSerial_TeamTeamSize.cpp | 11 +- .../serial/TestSerial_TeamVectorRange.cpp | 17 +- .../serial/TestSerial_UniqueToken.cpp | 46 + .../unit_test/serial/TestSerial_ViewAPI_a.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_b.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_c.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_d.cpp | 11 +- .../unit_test/serial/TestSerial_ViewAPI_e.cpp | 12 +- .../TestSerial_ViewLayoutStrideAssignment.cpp | 12 +- .../serial/TestSerial_ViewMapping_a.cpp | 12 +- .../serial/TestSerial_ViewMapping_b.cpp | 12 +- .../serial/TestSerial_ViewMapping_subview.cpp | 12 +- .../serial/TestSerial_ViewOfClass.cpp | 12 +- .../serial/TestSerial_ViewResize.cpp | 46 + .../serial/TestSerial_View_64bit.cpp | 11 +- .../unit_test/serial/TestSerial_WorkGraph.cpp | 15 +- lib/kokkos/core/unit_test/standalone/Makefile | 7 +- .../unit_test/standalone/UnitTestMainInit.cpp | 23 +- ...Threads_AtomicOperations_complexdouble.cpp | 16 +- ...tThreads_AtomicOperations_complexfloat.cpp | 16 +- .../TestThreads_AtomicOperations_double.cpp | 16 +- .../TestThreads_AtomicOperations_float.cpp | 16 +- .../TestThreads_AtomicOperations_int.cpp | 16 +- .../TestThreads_AtomicOperations_longint.cpp | 16 +- ...stThreads_AtomicOperations_longlongint.cpp | 16 +- ...stThreads_AtomicOperations_unsignedint.cpp | 16 +- ...reads_AtomicOperations_unsignedlongint.cpp | 16 +- .../threads/TestThreads_AtomicViews.cpp | 16 +- .../unit_test/threads/TestThreads_Atomics.cpp | 12 +- .../threads/TestThreads_Category.hpp | 25 +- .../unit_test/threads/TestThreads_Complex.cpp | 16 +- .../unit_test/threads/TestThreads_Crs.cpp | 15 +- .../threads/TestThreads_DeepCopyAlignment.cpp | 11 +- .../threads/TestThreads_FunctorAnalysis.cpp | 47 + .../unit_test/threads/TestThreads_Init.cpp | 21 +- .../threads/TestThreads_LocalDeepCopy.cpp | 12 +- .../threads/TestThreads_MDRange_a.cpp | 16 +- .../threads/TestThreads_MDRange_b.cpp | 16 +- .../threads/TestThreads_MDRange_c.cpp | 16 +- .../threads/TestThreads_MDRange_d.cpp | 16 +- .../threads/TestThreads_MDRange_e.cpp | 16 +- .../unit_test/threads/TestThreads_Other.cpp | 27 +- .../threads/TestThreads_RangePolicy.cpp | 16 +- .../threads/TestThreads_Reducers_a.cpp | 11 +- .../threads/TestThreads_Reducers_b.cpp | 11 +- .../threads/TestThreads_Reducers_c.cpp | 11 +- .../threads/TestThreads_Reducers_d.cpp | 11 +- .../threads/TestThreads_Reductions.cpp | 11 +- .../TestThreads_Reductions_DeviceView.cpp | 11 +- .../unit_test/threads/TestThreads_Scan.cpp | 16 +- .../threads/TestThreads_SharedAlloc.cpp | 19 +- .../threads/TestThreads_SubView_a.cpp | 77 +- .../threads/TestThreads_SubView_b.cpp | 35 +- .../threads/TestThreads_SubView_c01.cpp | 18 +- .../threads/TestThreads_SubView_c02.cpp | 19 +- .../threads/TestThreads_SubView_c03.cpp | 19 +- .../threads/TestThreads_SubView_c04.cpp | 18 +- .../threads/TestThreads_SubView_c05.cpp | 19 +- .../threads/TestThreads_SubView_c06.cpp | 19 +- .../threads/TestThreads_SubView_c07.cpp | 18 +- .../threads/TestThreads_SubView_c08.cpp | 19 +- .../threads/TestThreads_SubView_c09.cpp | 19 +- .../threads/TestThreads_SubView_c10.cpp | 18 +- .../threads/TestThreads_SubView_c11.cpp | 19 +- .../threads/TestThreads_SubView_c12.cpp | 19 +- .../threads/TestThreads_SubView_c13.cpp | 18 +- .../unit_test/threads/TestThreads_Team.cpp | 85 +- .../threads/TestThreads_TeamReductionScan.cpp | 64 +- .../threads/TestThreads_TeamScratch.cpp | 59 +- .../threads/TestThreads_TeamTeamSize.cpp | 13 +- .../threads/TestThreads_TeamVectorRange.cpp | 17 +- .../threads/TestThreads_UniqueToken.cpp | 46 + .../threads/TestThreads_ViewAPI_a.cpp | 11 +- .../threads/TestThreads_ViewAPI_b.cpp | 11 +- .../threads/TestThreads_ViewAPI_c.cpp | 11 +- .../threads/TestThreads_ViewAPI_d.cpp | 11 +- .../threads/TestThreads_ViewAPI_e.cpp | 11 +- ...TestThreads_ViewLayoutStrideAssignment.cpp | 12 +- .../threads/TestThreads_ViewMapping_a.cpp | 12 +- .../threads/TestThreads_ViewMapping_b.cpp | 12 +- .../TestThreads_ViewMapping_subview.cpp | 12 +- .../threads/TestThreads_ViewOfClass.cpp | 12 +- .../threads/TestThreads_ViewResize.cpp | 46 + .../threads/TestThreads_View_64bit.cpp | 11 +- .../threads/TestThreads_WorkGraph.cpp | 15 +- lib/kokkos/example/CMakeLists.txt | 28 +- .../CMakeLists.txt | 0 .../cmake_example.cpp | 17 +- .../foo.f | 0 .../build_cmake_installed/CMakeLists.txt | 42 + .../cmake_example.cpp} | 68 +- .../example/build_cmake_installed/foo.f | 4 + lib/kokkos/example/common/VectorImport.hpp | 294 - lib/kokkos/example/common/WrapMPI.hpp | 103 - lib/kokkos/example/feint/CMakeLists.txt | 18 - lib/kokkos/example/feint/ElemFunctor.hpp | 485 -- lib/kokkos/example/feint/Makefile | 71 - lib/kokkos/example/feint/feint.hpp | 165 - lib/kokkos/example/feint/feint_cuda.cpp | 67 - lib/kokkos/example/feint/feint_hpx.cpp | 67 - lib/kokkos/example/feint/feint_rocm.cpp | 67 - lib/kokkos/example/feint/feint_threads.cpp | 67 - lib/kokkos/example/fenl/CGSolve.hpp | 300 - lib/kokkos/example/fenl/CMakeLists.txt | 17 - lib/kokkos/example/fenl/Makefile | 50 - lib/kokkos/example/fenl/fenl.cpp | 181 - lib/kokkos/example/fenl/fenl.hpp | 89 - lib/kokkos/example/fenl/fenl_functors.hpp | 1173 ---- lib/kokkos/example/fenl/fenl_impl.hpp | 598 -- lib/kokkos/example/fenl/main.cpp | 367 -- lib/kokkos/example/fixture/BoxElemFixture.hpp | 355 -- lib/kokkos/example/fixture/BoxElemPart.cpp | 413 -- lib/kokkos/example/fixture/BoxElemPart.hpp | 320 - lib/kokkos/example/fixture/CMakeLists.txt | 13 - lib/kokkos/example/fixture/HexElement.hpp | 270 - lib/kokkos/example/fixture/Main.cpp | 307 - lib/kokkos/example/fixture/Makefile | 46 - lib/kokkos/example/fixture/TestFixture.hpp | 156 - .../example/global_2_local_ids/CMakeLists.txt | 17 - lib/kokkos/example/global_2_local_ids/G2L.hpp | 266 - .../example/global_2_local_ids/G2L_Main.cpp | 158 - .../example/global_2_local_ids/Makefile | 46 - lib/kokkos/example/grow_array/CMakeLists.txt | 14 - lib/kokkos/example/grow_array/Makefile | 46 - lib/kokkos/example/grow_array/grow_array.hpp | 257 - lib/kokkos/example/grow_array/main.cpp | 110 - lib/kokkos/example/make_buildlink/main.cpp | 13 +- lib/kokkos/example/md_skeleton/CMakeLists.txt | 16 - lib/kokkos/example/md_skeleton/Makefile | 46 - lib/kokkos/example/md_skeleton/README | 3 - lib/kokkos/example/md_skeleton/force.cpp | 184 - lib/kokkos/example/md_skeleton/main.cpp | 205 - lib/kokkos/example/md_skeleton/neighbor.cpp | 430 -- lib/kokkos/example/md_skeleton/setup.cpp | 271 - lib/kokkos/example/md_skeleton/system.h | 92 - lib/kokkos/example/md_skeleton/types.h | 118 - .../example/multi_fem/BoxMeshFixture.hpp | 610 -- .../example/multi_fem/BoxMeshPartition.cpp | 381 -- .../example/multi_fem/BoxMeshPartition.hpp | 210 - lib/kokkos/example/multi_fem/CMakeLists.txt | 16 - lib/kokkos/example/multi_fem/Explicit.hpp | 452 -- .../example/multi_fem/ExplicitFunctors.hpp | 1471 ----- lib/kokkos/example/multi_fem/FEMesh.hpp | 86 - lib/kokkos/example/multi_fem/HexElement.hpp | 268 - .../multi_fem/HexExplicitFunctions.hpp | 443 -- lib/kokkos/example/multi_fem/Implicit.hpp | 341 - .../example/multi_fem/ImplicitFunctors.hpp | 585 -- lib/kokkos/example/multi_fem/LinAlgBLAS.hpp | 567 -- lib/kokkos/example/multi_fem/Makefile | 49 - lib/kokkos/example/multi_fem/Nonlinear.hpp | 573 -- .../multi_fem/NonlinearElement_Cuda.hpp | 390 -- .../example/multi_fem/NonlinearFunctors.hpp | 482 -- lib/kokkos/example/multi_fem/ParallelComm.hpp | 167 - .../example/multi_fem/ParallelDataMap.hpp | 517 -- .../example/multi_fem/ParallelMachine.cpp | 178 - .../example/multi_fem/ParallelMachine.hpp | 118 - .../example/multi_fem/SparseLinearSystem.hpp | 404 -- .../multi_fem/SparseLinearSystemFill.hpp | 276 - .../multi_fem/SparseLinearSystem_Cuda.hpp | 164 - .../example/multi_fem/TestBoxMeshFixture.hpp | 242 - .../multi_fem/TestBoxMeshPartition.cpp | 172 - lib/kokkos/example/multi_fem/TestCuda.cpp | 188 - lib/kokkos/example/multi_fem/TestHost.cpp | 142 - .../example/multi_fem/TestHybridFEM.cpp | 348 -- .../example/query_device/CMakeLists.txt | 10 +- .../example/query_device/query_device.cpp | 58 +- lib/kokkos/example/sort_array/CMakeLists.txt | 14 - lib/kokkos/example/sort_array/Makefile | 46 - lib/kokkos/example/sort_array/main.cpp | 95 - lib/kokkos/example/sort_array/sort_array.hpp | 190 - .../tutorial/01_hello_world/CMakeLists.txt | 9 +- .../tutorial/01_hello_world/hello_world.cpp | 36 +- .../01_hello_world_lambda/CMakeLists.txt | 17 +- .../hello_world_lambda.cpp | 31 +- .../tutorial/02_simple_reduce/CMakeLists.txt | 9 +- .../02_simple_reduce/simple_reduce.cpp | 46 +- .../02_simple_reduce_lambda/CMakeLists.txt | 17 +- .../simple_reduce_lambda.cpp | 49 +- .../tutorial/03_simple_view/CMakeLists.txt | 9 +- .../example/tutorial/03_simple_view/Makefile | 2 +- .../tutorial/03_simple_view/simple_view.cpp | 56 +- .../03_simple_view_lambda/CMakeLists.txt | 6 +- .../simple_view_lambda.cpp | 78 +- .../04_simple_memoryspaces/CMakeLists.txt | 5 +- .../simple_memoryspaces.cpp | 44 +- .../tutorial/05_simple_atomics/CMakeLists.txt | 6 +- .../05_simple_atomics/simple_atomics.cpp | 76 +- .../06_simple_mdrangepolicy/CMakeLists.txt | 6 +- .../simple_mdrangepolicy.cpp | 130 +- .../01_data_layouts/CMakeLists.txt | 5 +- .../01_data_layouts/data_layouts.cpp | 72 +- .../02_memory_traits/CMakeLists.txt | 5 +- .../02_memory_traits/memory_traits.cpp | 86 +- .../Advanced_Views/03_subviews/CMakeLists.txt | 5 +- .../Advanced_Views/03_subviews/subviews.cpp | 108 +- .../04_dualviews/CMakeLists.txt | 5 +- .../Advanced_Views/04_dualviews/dual_view.cpp | 209 +- .../05_NVIDIA_UVM/CMakeLists.txt | 14 +- .../05_NVIDIA_UVM/uvm_example.cpp | 91 +- .../overlapping_deepcopy.cpp | 129 +- .../tutorial/Advanced_Views/CMakeLists.txt | 12 +- .../01_random_numbers/random_numbers.cpp | 182 +- lib/kokkos/example/tutorial/CMakeLists.txt | 22 +- .../01_thread_teams/CMakeLists.txt | 5 +- .../01_thread_teams/thread_teams.cpp | 67 +- .../01_thread_teams_lambda/CMakeLists.txt | 13 +- .../thread_teams_lambda.cpp | 53 +- .../02_nested_parallel_for/CMakeLists.txt | 5 +- .../nested_parallel_for.cpp | 81 +- .../03_vectorization/CMakeLists.txt | 10 +- .../03_vectorization/vectorization.cpp | 156 +- .../04_team_scan/CMakeLists.txt | 6 +- .../04_team_scan/team_scan.cpp | 151 +- .../Hierarchical_Parallelism/CMakeLists.txt | 10 +- .../tutorial/launch_bounds/CMakeLists.txt | 5 +- .../launch_bounds/launch_bounds_reduce.cpp | 199 +- .../example/virtual_functions/classes.cpp | 22 +- .../example/virtual_functions/classes.hpp | 48 +- lib/kokkos/example/virtual_functions/main.cpp | 52 +- lib/kokkos/generate_makefile.bash | 100 +- lib/kokkos/master_history.txt | 1 + 2169 files changed, 121961 insertions(+), 127047 deletions(-) create mode 100644 lib/kokkos/BUILD.md create mode 100644 lib/kokkos/CONTRIBUTING.md delete mode 100644 lib/kokkos/README create mode 100644 lib/kokkos/README.md create mode 100755 lib/kokkos/cm_generate_makefile.bash create mode 100644 lib/kokkos/cmake/KokkosConfigCommon.cmake.in create mode 100644 lib/kokkos/cmake/KokkosCore_config.h.in delete mode 100644 lib/kokkos/cmake/Makefile.generate_cmake_settings delete mode 100644 lib/kokkos/cmake/Modules/FindHWLOC.cmake delete mode 100644 lib/kokkos/cmake/Modules/FindMemkind.cmake delete mode 100644 lib/kokkos/cmake/Modules/FindQthreads.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLCUDA.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLHPX.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake create mode 100644 lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake create mode 100644 lib/kokkos/cmake/README.md create mode 100644 lib/kokkos/cmake/compile_tests/clang_omp.cpp create mode 100644 lib/kokkos/cmake/compile_tests/pthread.cpp create mode 100644 lib/kokkos/cmake/cray.cmake delete mode 100644 lib/kokkos/cmake/deps/QTHREADS.cmake create mode 100644 lib/kokkos/cmake/fake_tribits.cmake create mode 100644 lib/kokkos/cmake/gnu.cmake create mode 100644 lib/kokkos/cmake/intel.cmake create mode 100644 lib/kokkos/cmake/kokkos_arch.cmake delete mode 100644 lib/kokkos/cmake/kokkos_build.cmake create mode 100644 lib/kokkos/cmake/kokkos_compiler_id.cmake create mode 100644 lib/kokkos/cmake/kokkos_corner_cases.cmake create mode 100644 lib/kokkos/cmake/kokkos_enable_devices.cmake create mode 100644 lib/kokkos/cmake/kokkos_enable_options.cmake create mode 100644 lib/kokkos/cmake/kokkos_install.cmake delete mode 100644 lib/kokkos/cmake/kokkos_options.cmake create mode 100644 lib/kokkos/cmake/kokkos_pick_cxx_std.cmake delete mode 100644 lib/kokkos/cmake/kokkos_settings.cmake create mode 100644 lib/kokkos/cmake/kokkos_test_cxx_std.cmake create mode 100644 lib/kokkos/cmake/kokkos_tpls.cmake create mode 100644 lib/kokkos/cmake/kokkos_tribits.cmake create mode 100644 lib/kokkos/cmake/pgi.cmake delete mode 100644 lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake delete mode 100644 lib/kokkos/cmake/tribits.cmake create mode 100644 lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp delete mode 100644 lib/kokkos/core/src/Makefile delete mode 100644 lib/kokkos/core/src/Makefile.generate_build_files delete mode 100644 lib/kokkos/core/src/Makefile.generate_header_lists create mode 100644 lib/kokkos/core/src/dummy.cpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_MemorySpace.hpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Stacktrace.cpp create mode 100644 lib/kokkos/core/src/impl/Kokkos_Stacktrace.hpp rename lib/kokkos/{example/feint/feint_fwd.hpp => core/unit_test/TestStackTrace.cpp} (69%) create mode 100644 lib/kokkos/core/unit_test/TestStackTrace.hpp rename lib/kokkos/{example/feint/feint_openmp.cpp => core/unit_test/TestStackTrace_f0.cpp} (67%) rename lib/kokkos/{example/fixture/TestFixture.cpp => core/unit_test/TestStackTrace_f1.cpp} (69%) rename lib/kokkos/{example/feint/feint_serial.cpp => core/unit_test/TestStackTrace_f2.cpp} (67%) create mode 100644 lib/kokkos/core/unit_test/TestStackTrace_f3.cpp create mode 100644 lib/kokkos/core/unit_test/TestStackTrace_f4.cpp create mode 100644 lib/kokkos/core/unit_test/TestViewResize.hpp create mode 100644 lib/kokkos/core/unit_test/configuration/test-code/CMakeLists.txt create mode 100644 lib/kokkos/core/unit_test/configuration/test-code/Makefile create mode 100644 lib/kokkos/core/unit_test/configuration/test-code/main.cpp create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_arch_list.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_device_list.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_options_list.bash create mode 100755 lib/kokkos/core/unit_test/configuration/test-code/test_config_run.bash create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_DebugPinUVMSpace.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_DebugSerialExecution.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/cuda/TestCuda_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_AtomicOperations_complexdouble.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_AtomicOperations_complexfloat.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_DeepCopyAlignment.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_LocalDeepCopy.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_Reductions_DeviceView.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_TeamTeamSize.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_ViewLayoutStrideAssignment.cpp create mode 100644 lib/kokkos/core/unit_test/hpx/TestHPX_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/openmp/TestOpenMP_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/openmp/TestOpenMP_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_UniqueToken.cpp create mode 100644 lib/kokkos/core/unit_test/serial/TestSerial_ViewResize.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_FunctorAnalysis.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_UniqueToken.cpp create mode 100644 lib/kokkos/core/unit_test/threads/TestThreads_ViewResize.cpp rename lib/kokkos/example/{cmake_build => build_cmake_in_tree}/CMakeLists.txt (100%) rename lib/kokkos/example/{cmake_build => build_cmake_in_tree}/cmake_example.cpp (85%) rename lib/kokkos/example/{cmake_build => build_cmake_in_tree}/foo.f (100%) create mode 100644 lib/kokkos/example/build_cmake_installed/CMakeLists.txt rename lib/kokkos/example/{feint/main.cpp => build_cmake_installed/cmake_example.cpp} (55%) create mode 100644 lib/kokkos/example/build_cmake_installed/foo.f delete mode 100644 lib/kokkos/example/common/VectorImport.hpp delete mode 100644 lib/kokkos/example/common/WrapMPI.hpp delete mode 100644 lib/kokkos/example/feint/CMakeLists.txt delete mode 100644 lib/kokkos/example/feint/ElemFunctor.hpp delete mode 100644 lib/kokkos/example/feint/Makefile delete mode 100644 lib/kokkos/example/feint/feint.hpp delete mode 100644 lib/kokkos/example/feint/feint_cuda.cpp delete mode 100644 lib/kokkos/example/feint/feint_hpx.cpp delete mode 100644 lib/kokkos/example/feint/feint_rocm.cpp delete mode 100644 lib/kokkos/example/feint/feint_threads.cpp delete mode 100644 lib/kokkos/example/fenl/CGSolve.hpp delete mode 100644 lib/kokkos/example/fenl/CMakeLists.txt delete mode 100644 lib/kokkos/example/fenl/Makefile delete mode 100644 lib/kokkos/example/fenl/fenl.cpp delete mode 100644 lib/kokkos/example/fenl/fenl.hpp delete mode 100644 lib/kokkos/example/fenl/fenl_functors.hpp delete mode 100644 lib/kokkos/example/fenl/fenl_impl.hpp delete mode 100644 lib/kokkos/example/fenl/main.cpp delete mode 100644 lib/kokkos/example/fixture/BoxElemFixture.hpp delete mode 100644 lib/kokkos/example/fixture/BoxElemPart.cpp delete mode 100644 lib/kokkos/example/fixture/BoxElemPart.hpp delete mode 100644 lib/kokkos/example/fixture/CMakeLists.txt delete mode 100644 lib/kokkos/example/fixture/HexElement.hpp delete mode 100644 lib/kokkos/example/fixture/Main.cpp delete mode 100644 lib/kokkos/example/fixture/Makefile delete mode 100644 lib/kokkos/example/fixture/TestFixture.hpp delete mode 100644 lib/kokkos/example/global_2_local_ids/CMakeLists.txt delete mode 100644 lib/kokkos/example/global_2_local_ids/G2L.hpp delete mode 100644 lib/kokkos/example/global_2_local_ids/G2L_Main.cpp delete mode 100644 lib/kokkos/example/global_2_local_ids/Makefile delete mode 100644 lib/kokkos/example/grow_array/CMakeLists.txt delete mode 100644 lib/kokkos/example/grow_array/Makefile delete mode 100644 lib/kokkos/example/grow_array/grow_array.hpp delete mode 100644 lib/kokkos/example/grow_array/main.cpp delete mode 100644 lib/kokkos/example/md_skeleton/CMakeLists.txt delete mode 100644 lib/kokkos/example/md_skeleton/Makefile delete mode 100644 lib/kokkos/example/md_skeleton/README delete mode 100644 lib/kokkos/example/md_skeleton/force.cpp delete mode 100644 lib/kokkos/example/md_skeleton/main.cpp delete mode 100644 lib/kokkos/example/md_skeleton/neighbor.cpp delete mode 100644 lib/kokkos/example/md_skeleton/setup.cpp delete mode 100644 lib/kokkos/example/md_skeleton/system.h delete mode 100644 lib/kokkos/example/md_skeleton/types.h delete mode 100644 lib/kokkos/example/multi_fem/BoxMeshFixture.hpp delete mode 100644 lib/kokkos/example/multi_fem/BoxMeshPartition.cpp delete mode 100644 lib/kokkos/example/multi_fem/BoxMeshPartition.hpp delete mode 100644 lib/kokkos/example/multi_fem/CMakeLists.txt delete mode 100644 lib/kokkos/example/multi_fem/Explicit.hpp delete mode 100644 lib/kokkos/example/multi_fem/ExplicitFunctors.hpp delete mode 100644 lib/kokkos/example/multi_fem/FEMesh.hpp delete mode 100644 lib/kokkos/example/multi_fem/HexElement.hpp delete mode 100644 lib/kokkos/example/multi_fem/HexExplicitFunctions.hpp delete mode 100644 lib/kokkos/example/multi_fem/Implicit.hpp delete mode 100644 lib/kokkos/example/multi_fem/ImplicitFunctors.hpp delete mode 100644 lib/kokkos/example/multi_fem/LinAlgBLAS.hpp delete mode 100644 lib/kokkos/example/multi_fem/Makefile delete mode 100644 lib/kokkos/example/multi_fem/Nonlinear.hpp delete mode 100644 lib/kokkos/example/multi_fem/NonlinearElement_Cuda.hpp delete mode 100644 lib/kokkos/example/multi_fem/NonlinearFunctors.hpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelComm.hpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelDataMap.hpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelMachine.cpp delete mode 100644 lib/kokkos/example/multi_fem/ParallelMachine.hpp delete mode 100644 lib/kokkos/example/multi_fem/SparseLinearSystem.hpp delete mode 100644 lib/kokkos/example/multi_fem/SparseLinearSystemFill.hpp delete mode 100644 lib/kokkos/example/multi_fem/SparseLinearSystem_Cuda.hpp delete mode 100644 lib/kokkos/example/multi_fem/TestBoxMeshFixture.hpp delete mode 100644 lib/kokkos/example/multi_fem/TestBoxMeshPartition.cpp delete mode 100644 lib/kokkos/example/multi_fem/TestCuda.cpp delete mode 100644 lib/kokkos/example/multi_fem/TestHost.cpp delete mode 100644 lib/kokkos/example/multi_fem/TestHybridFEM.cpp delete mode 100644 lib/kokkos/example/sort_array/CMakeLists.txt delete mode 100644 lib/kokkos/example/sort_array/Makefile delete mode 100644 lib/kokkos/example/sort_array/main.cpp delete mode 100644 lib/kokkos/example/sort_array/sort_array.hpp diff --git a/lib/kokkos/BUILD.md b/lib/kokkos/BUILD.md new file mode 100644 index 0000000000..c4d6c98365 --- /dev/null +++ b/lib/kokkos/BUILD.md @@ -0,0 +1,323 @@ +![Kokkos](https://avatars2.githubusercontent.com/u/10199860?s=200&v=4) + +# Installing and Using Kokkos + +## Kokkos Philosophy +Kokkos provides a modern CMake style build system. +As C++ continues to develop for C++20 and beyond, CMake is likely to provide the most robust support +for C++. Applications heavily leveraging Kokkos are strongly encouraged to use a CMake build system. + +You can either use Kokkos as an installed package (encouraged) or use Kokkos in-tree in your project. +Modern CMake is exceedingly simple at a high-level (with the devil in the details). +Once Kokkos is installed In your `CMakeLists.txt` simply use: +```` +find_package(Kokkos REQUIRED) +```` +Then for every executable or library in your project: +```` +target_link_libraries(myTarget Kokkos::kokkos) +```` +That's it! There is no checking Kokkos preprocessor, compiler, or linker flags. +Kokkos propagates all the necesssary flags to your project. +This means not only is linking to Kokkos easy, but Kokkos itself can actually configure compiler and linker flags for *your* +project. If building in-tree, there is no `find_package` and you link with `target_link_libraries(kokkos)`. + + +## Configuring CMake +A very basic installation is done with: +```` +cmake ${srcdir} \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX=${my_install_folder} +```` +which builds and installed a default Kokkos when you run `make install`. +There are numerous device backends, options, and architecture-specific optimizations that can be configured, e.g. +```` +cmake ${srcdir} \ + -DCMAKE_CXX_COMPILER=g++ \ + -DCMAKE_INSTALL_PREFIX=${my_install_folder} \ + -DKokkos_ENABLE_OPENMP=On +```` +which activates the OpenMP backend. All of the options controlling device backends, options, architectures, and third-party libraries (TPLs) are given below. + +## Spack +An alternative to manually building with the CMake is to use the Spack package manager. +To do so, download the `kokkos-spack` git repo and add to the package list: +```` +spack repo add $path-to-kokkos-spack +```` +A basic installation would be done as: +```` +spack install kokkos +```` +Spack allows options and and compilers to be tuned in the install command. +```` +spack install kokkos@3.0 %gcc@7.3.0 +openmp +```` +This example illustrates the three most common parameters to Spack: +* Variants: specified with, e.g. `+openmp`, this activates (or deactivates with, e.g. `~openmp`) certain options. +* Version: immediately following `kokkos` the `@version` can specify a particular Kokkos to build +* Compiler: a default compiler will be chosen if not specified, but an exact compiler version can be given with the `%`option. + +For a complete list of Kokkos options, run: +```` +spack info kokkos +```` + +#### Spack Development +Spack currently installs packages to a location determined by a unique hash. This hash name is not really "human readable". +Generally, Spack usage should never really require you to reference the computer-generated unique install folder. +If you must know, you can locate Spack Kokkos installations with: +```` +spack find -p kokkos ... +```` +where `...` is the unique spec identifying the particular Kokkos configuration and version. + +A better way to use Spack for doing Kokkos development is the DIY feature of Spack. +If you wish to develop Kokkos itself, go to the Kokkos source folder: +```` +spack diy -u cmake kokkos@diy ... +```` +where `...` is a Spack spec identifying the exact Kokkos configuration. +This then creates a `spack-build` directory where you can run `make`. + +If doing development on a downstream project, you can do almost exactly the same thing. +```` +spack diy -u cmake ${myproject}@${myversion} ... ^kokkos... +```` +where the `...` are the specs for your project and the desired Kokkos configuration. +Again, a `spack-build` directory will be created where you can run `make`. + +Spack has a few idiosyncracies that make building outside of Spack annoying related to Spack forcing use of a compiler wrapper. This can be worked around by having a `-DSpack_WORKAROUND=On` given your CMake. Then add the block of code to your CMakeLists.txt: + +```` +if (Spack_WORKAROUND) + set(SPACK_CXX $ENV{SPACK_CXX}) + if(SPACK_CXX) + set(CMAKE_CXX_COMPILER ${SPACK_CXX} CACHE STRING "the C++ compiler" FORCE) + set(ENV{CXX} ${SPACK_CXX}) + endif() +endif() +```` + +# Kokkos Keyword Listing + +## Device Backends +Device backends can be enabled by specifiying `-DKokkos_ENABLE_X`. + +* Kokkos_ENABLE_CUDA + * Whether to build CUDA backend + * BOOL Default: OFF +* Kokkos_ENABLE_HPX + * Whether to build HPX backend (experimental) + * BOOL Default: OFF +* Kokkos_ENABLE_OPENMP + * Whether to build OpenMP backend + * BOOL Default: OFF +* Kokkos_ENABLE_PTHREAD + * Whether to build Pthread backend + * BOOL Default: OFF +* Kokkos_ENABLE_SERIAL + * Whether to build serial backend + * BOOL Default: ON + +## Enable Options +Options can be enabled by specifiying `-DKokkos_ENABLE_X`. + +* Kokkos_ENABLE_AGGRESSIVE_VECTORIZATION + * Whether to aggressively vectorize loops + * BOOL Default: OFF +* Kokkos_ENABLE_COMPILER_WARNINGS + * Whether to print all compiler warnings + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_CONSTEXPR + * Whether to activate experimental relaxed constexpr functions + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_LAMBDA + * Whether to activate experimental lambda features + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_LDG_INTRINSIC + * Whether to use CUDA LDG intrinsics + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE + * Whether to enable relocatable device code (RDC) for CUDA + * BOOL Default: OFF +* Kokkos_ENABLE_CUDA_UVM + * Whether to use unified memory (UM) by default for CUDA + * BOOL Default: OFF +* Kokkos_ENABLE_DEBUG + * Whether to activate extra debug features - may increase compile times + * BOOL Default: OFF +* Kokkos_ENABLE_DEBUG_BOUNDS_CHECK + * Whether to use bounds checking - will increase runtime + * BOOL Default: OFF +* Kokkos_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK + * Debug check on dual views + * BOOL Default: OFF +* Kokkos_ENABLE_DEPRECATED_CODE + * Whether to enable deprecated code + * BOOL Default: OFF +* Kokkos_ENABLE_HPX_ASYNC_DISPATCH + * Whether HPX supports asynchronous dispatch + * BOOL Default: OFF +* Kokkos_ENABLE_LARGE_MEM_TESTS + * Whether to perform extra large memory tests + * BOOL_Default: OFF +* Kokkos_ENABLE_PROFILING + * Whether to create bindings for profiling tools + * BOOL Default: ON +* Kokkos_ENABLE_PROFILING_LOAD_PRINT + * Whether to print information about which profiling tools gotloaded + * BOOL Default: OFF +* Kokkos_ENABLE_TESTS + * Whether to build serial backend + * BOOL Default: OFF + +## Other Options +* Kokkos_CXX_STANDARD + * The C++ standard for Kokkos to use: c++11, c++14, c++17, or c++20. This should be given in CMake style as 11, 14, 17, or 20. + * STRING Default: 11 + +## Third-party Libraries (TPLs) +The following options control enabling TPLs: +* Kokkos_ENABLE_HPX + * Whether to enable the HPX library + * BOOL Default: OFF +* Kokkos_ENABLE_HWLOC + * Whether to enable the HWLOC library + * BOOL Default: Off +* Kokkos_ENABLE_LIBNUMA + * Whether to enable the LIBNUMA library + * BOOL Default: Off +* Kokkos_ENABLE_MEMKIND + * Whether to enable the MEMKIND library + * BOOL Default: Off +* Kokkos_ENABLE_LIBDL + * Whether to enable the LIBDL library + * BOOL Default: On +* Kokkos_ENABLE_LIBRT + * Whether to enable the LIBRT library + * BOOL Default: Off + +The following options control finding and configuring non-CMake TPLs: +* Kokkos_CUDA_DIR or CUDA_ROOT + * Location of CUDA install prefix for libraries + * PATH Default: +* Kokkos_HWLOC_DIR or HWLOC_ROOT + * Location of HWLOC install prefix + * PATH Default: +* Kokkos_LIBNUMA_DIR or LIBNUMA_ROOT + * Location of LIBNUMA install prefix + * PATH Default: +* Kokkos_MEMKIND_DIR or MEMKIND_ROOT + * Location of MEMKIND install prefix + * PATH Default: +* Kokkos_LIBDL_DIR or LIBDL_ROOT + * Location of LIBDL install prefix + * PATH Default: +* Kokkos_LIBRT_DIR or LIBRT_ROOT + * Location of LIBRT install prefix + * PATH Default: + +The following options control `find_package` paths for CMake-based TPLs: +* HPX_DIR or HPX_ROOT + * Location of HPX prefix (ROOT) or CMake config file (DIR) + * PATH Default: + +## Architecture Keywords +Architecture-specific optimizations can be enabled by specifiying `-DKokkos_ARCH_X`. + +* Kokkos_ARCH_AMDAVX + * Whether to optimize for the AMDAVX architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV80 + * Whether to optimize for the ARMV80 architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV81 + * Whether to optimize for the ARMV81 architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV8_THUNDERX + * Whether to optimize for the ARMV8_THUNDERX architecture + * BOOL Default: OFF +* Kokkos_ARCH_ARMV8_TX2 + * Whether to optimize for the ARMV8_TX2 architecture + * BOOL Default: OFF +* Kokkos_ARCH_BDW + * Whether to optimize for the BDW architecture + * BOOL Default: OFF +* Kokkos_ARCH_BGQ + * Whether to optimize for the BGQ architecture + * BOOL Default: OFF +* Kokkos_ARCH_EPYC + * Whether to optimize for the EPYC architecture + * BOOL Default: OFF +* Kokkos_ARCH_HSW + * Whether to optimize for the HSW architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER30 + * Whether to optimize for the KEPLER30 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER32 + * Whether to optimize for the KEPLER32 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER35 + * Whether to optimize for the KEPLER35 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KEPLER37 + * Whether to optimize for the KEPLER37 architecture + * BOOL Default: OFF +* Kokkos_ARCH_KNC + * Whether to optimize for the KNC architecture + * BOOL Default: OFF +* Kokkos_ARCH_KNL + * Whether to optimize for the KNL architecture + * BOOL Default: OFF +* Kokkos_ARCH_MAXWELL50 + * Whether to optimize for the MAXWELL50 architecture + * BOOL Default: OFF +* Kokkos_ARCH_MAXWELL52 + * Whether to optimize for the MAXWELL52 architecture + * BOOL Default: OFF +* Kokkos_ARCH_MAXWELL53 + * Whether to optimize for the MAXWELL53 architecture + * BOOL Default: OFF +* Kokkos_ARCH_PASCAL60 + * Whether to optimize for the PASCAL60 architecture + * BOOL Default: OFF +* Kokkos_ARCH_PASCAL61 + * Whether to optimize for the PASCAL61 architecture + * BOOL Default: OFF +* Kokkos_ARCH_POWER7 + * Whether to optimize for the POWER7 architecture + * BOOL Default: OFF +* Kokkos_ARCH_POWER8 + * Whether to optimize for the POWER8 architecture + * BOOL Default: OFF +* Kokkos_ARCH_POWER9 + * Whether to optimize for the POWER9 architecture + * BOOL Default: OFF +* Kokkos_ARCH_SKX + * Whether to optimize for the SKX architecture + * BOOL Default: OFF +* Kokkos_ARCH_SNB + * Whether to optimize for the SNB architecture + * BOOL Default: OFF +* Kokkos_ARCH_TURING75 + * Whether to optimize for the TURING75 architecture + * BOOL Default: OFF +* Kokkos_ARCH_VOLTA70 + * Whether to optimize for the VOLTA70 architecture + * BOOL Default: OFF +* Kokkos_ARCH_VOLTA72 + * Whether to optimize for the VOLTA72 architecture + * BOOL Default: OFF +* Kokkos_ARCH_WSM + * Whether to optimize for the WSM architecture + * BOOL Default: OFF + +##### [LICENSE](https://github.com/kokkos/kokkos/blob/devel/LICENSE) + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) + +Under the terms of Contract DE-NA0003525 with NTESS, +the U.S. Government retains certain rights in this software. diff --git a/lib/kokkos/CHANGELOG.md b/lib/kokkos/CHANGELOG.md index 8d196e2c35..459aeb3d2e 100644 --- a/lib/kokkos/CHANGELOG.md +++ b/lib/kokkos/CHANGELOG.md @@ -1,5 +1,45 @@ # Change Log +## [3.0.00](https://github.com/kokkos/kokkos/tree/3.0.00) (2020-01-27) +[Full Changelog](https://github.com/kokkos/kokkos/compare/2.9.00...3.0.00) + +**Implemented enhancements:** + +- BuildSystem: Standalone Modern CMake Support [\#2104](https://github.com/kokkos/kokkos/issues/2104) +- StyleFormat: ClangFormat Style [\#2157](https://github.com/kokkos/kokkos/issues/2157) +- Documentation: Document build system and CMake philosophy [\#2263](https://github.com/kokkos/kokkos/issues/2263) +- BuildSystem: Add Alias with Namespace Kokkos:: to Interal Libraries [\#2530](https://github.com/kokkos/kokkos/issues/2530) +- BuildSystem: Universal Kokkos find\_package [\#2099](https://github.com/kokkos/kokkos/issues/2099) +- BuildSystem: Dropping support for Kokkos\_{DEVICES,OPTIONS,ARCH} in CMake [\#2329](https://github.com/kokkos/kokkos/issues/2329) +- BuildSystem: Set Kokkos\_DEVICES and Kokkos\_ARCH variables in exported CMake configuration [\#2193](https://github.com/kokkos/kokkos/issues/2193) +- BuildSystem: Drop support for CUDA 7 and CUDA 8 [\#2489](https://github.com/kokkos/kokkos/issues/2489) +- BuildSystem: Drop CMake option SEPARATE\_TESTS [\#2266](https://github.com/kokkos/kokkos/issues/2266) +- BuildSystem: Support expt-relaxed-constexpr same as expt-extended-lambda [\#2411](https://github.com/kokkos/kokkos/issues/2411) +- BuildSystem: Add Xnvlink to command line options allowed in nvcc\_wrapper [\#2197](https://github.com/kokkos/kokkos/issues/2197) +- BuildSystem: Install Kokkos config files and target files to lib/cmake/Kokkos [\#2162](https://github.com/kokkos/kokkos/issues/2162) +- BuildSystem: nvcc\_wrappers and c++ 14 [\#2035](https://github.com/kokkos/kokkos/issues/2035) +- BuildSystem: Kokkos version major/version minor \(Feature request\) [\#1930](https://github.com/kokkos/kokkos/issues/1930) +- BuildSystem: CMake namespaces \(and other modern cmake cleanup\) [\#1924](https://github.com/kokkos/kokkos/issues/1924) +- BuildSystem: Remove capability to install Kokkos via GNU Makefiles [\#2332](https://github.com/kokkos/kokkos/issues/2332) +- Documentation: Remove PDF ProgrammingGuide in Kokkos replace with link [\#2244](https://github.com/kokkos/kokkos/issues/2244) +- View: Add Method to Resize View without Initialization [\#2048](https://github.com/kokkos/kokkos/issues/2048) +- Vector: implement “insert†method for Kokkos\_Vector \(as a serial function on host\) [\#2437](https://github.com/kokkos/kokkos/issues/2437) + +**Fixed bugs:** + +- ParallelScan: Kokkos::parallel\scan fix race condition seen in inter-block fence [\#2681](https://github.com/kokkos/kokkos/issues/2681) +- OffsetView: Kokkos::OffsetView missing constructor which takes pointer [\#2247](https://github.com/kokkos/kokkos/issues/2247) +- OffsetView: Kokkos::OffsetView: allow offset=0 [\#2246](https://github.com/kokkos/kokkos/issues/2246) +- DeepCopy: Missing DeepCopy instrumentation in Kokkos [\#2522](https://github.com/kokkos/kokkos/issues/2522) +- nvcc\_wrapper: --host-only fails with mutiple -W\* flags [\#2484](https://github.com/kokkos/kokkos/issues/2484) +- nvcc\_wrapper: taking first -std option is counterintuitive [\#2553](https://github.com/kokkos/kokkos/issues/2553) +- Subview: Error taking subviews of views with static_extents of min rank [\#2448](https://github.com/kokkos/kokkos/issues/2448) +- TeamPolicy: reducers with valuetypes without += broken on CUDA [\#2410](https://github.com/kokkos/kokkos/issues/2410) +- Libs: Fix inconsistency of Kokkos library names in Kokkos and Trilinos [\#1902](https://github.com/kokkos/kokkos/issues/1902) +- Complex: operator\>\> for complex\ uses std::ostream, not std::istream [\#2313](https://github.com/kokkos/kokkos/issues/2313) +- Macros: Restrict not honored for non-intel compilers [\#1922](https://github.com/kokkos/kokkos/issues/1922) + + ## [2.9.00](https://github.com/kokkos/kokkos/tree/2.9.00) (2019-06-24) [Full Changelog](https://github.com/kokkos/kokkos/compare/2.8.00...2.9.00) diff --git a/lib/kokkos/CMakeLists.txt b/lib/kokkos/CMakeLists.txt index 236f523aec..6a4451b2e7 100644 --- a/lib/kokkos/CMakeLists.txt +++ b/lib/kokkos/CMakeLists.txt @@ -1,128 +1,218 @@ -# Is this a build as part of Trilinos? +# We want to determine if options are given with the wrong case +# In order to detect which arguments are given to compare against +# the list of valid arguments, at the beginning here we need to +# form a list of all the given variables. If it begins with any +# case of KoKkOS, we add it to the list. + + +GET_CMAKE_PROPERTY(_variableNames VARIABLES) +SET(KOKKOS_GIVEN_VARIABLES) +FOREACH (var ${_variableNames}) + STRING(TOUPPER ${var} UC_VAR) + STRING(FIND ${UC_VAR} KOKKOS IDX) + IF (${IDX} EQUAL 0) + LIST(APPEND KOKKOS_GIVEN_VARIABLES ${var}) + ENDIF() +ENDFOREACH() + +# Basic initialization (Used in KOKKOS_SETTINGS) +SET(Kokkos_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +SET(KOKKOS_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +SET(KOKKOS_SRC_PATH ${Kokkos_SOURCE_DIR}) +SET(KOKKOS_PATH ${Kokkos_SOURCE_DIR}) +SET(KOKKOS_TOP_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) + +# Needed to simplify syntax of if statements +CMAKE_POLICY(SET CMP0054 NEW) + +# Is this a build as part of Trilinos? IF(COMMAND TRIBITS_PACKAGE_DECL) - SET(KOKKOS_HAS_TRILINOS ON CACHE BOOL "") + SET(KOKKOS_HAS_TRILINOS ON) ELSE() - SET(KOKKOS_HAS_TRILINOS OFF CACHE BOOL "") + SET(KOKKOS_HAS_TRILINOS OFF) ENDIF() -IF(NOT KOKKOS_HAS_TRILINOS) - cmake_minimum_required(VERSION 3.3 FATAL_ERROR) +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_functions.cmake) +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_pick_cxx_std.cmake) + +SET(KOKKOS_ENABLED_OPTIONS) #exported in config file +SET(KOKKOS_ENABLED_DEVICES) #exported in config file +SET(KOKKOS_ENABLED_TPLS) #exported in config file +SET(KOKKOS_ENABLED_ARCH_LIST) #exported in config file + +#These are helper flags used for sanity checks during config +#Certain features should depend on other features being configured first +SET(KOKKOS_CFG_DAG_NONE On) #sentinel to indicate no dependencies +SET(KOKKOS_CFG_DAG_DEVICES_DONE Off) +SET(KOKKOS_CFG_DAG_OPTIONS_DONE Off) +SET(KOKKOS_CFG_DAG_ARCH_DONE Off) +SET(KOKKOS_CFG_DAG_CXX_STD_DONE Off) +SET(KOKKOS_CFG_DAG_COMPILER_ID_DONE Off) +FUNCTION(KOKKOS_CFG_DEPENDS SUCCESSOR PRECURSOR) + SET(PRE_FLAG KOKKOS_CFG_DAG_${PRECURSOR}) + SET(POST_FLAG KOKKOS_CFG_DAG_${SUCCESSOR}) + IF (NOT ${PRE_FLAG}) + MESSAGE(FATAL_ERROR "Bad CMake refactor: feature ${SUCCESSOR} cannot be configured until ${PRECURSOR} is configured") + ENDIF() + GLOBAL_SET(${POST_FLAG} On) +ENDFUNCTION() - # Define Project Name if this is a standalone build + +LIST(APPEND CMAKE_MODULE_PATH cmake/Modules) + +IF(NOT KOKKOS_HAS_TRILINOS) + cmake_minimum_required(VERSION 3.10 FATAL_ERROR) + set(CMAKE_DISABLE_SOURCE_CHANGES ON) + set(CMAKE_DISABLE_IN_SOURCE_BUILD ON) + IF (Spack_WORKAROUND) + #if we are explicitly using Spack for development, + #nuke the Spack compiler + SET(SPACK_CXX $ENV{SPACK_CXX}) + IF(SPACK_CXX) + SET(CMAKE_CXX_COMPILER ${SPACK_CXX} CACHE STRING "the C++ compiler" FORCE) + SET(ENV{CXX} ${SPACK_CXX}) + ENDIF() + ENDif() IF(NOT DEFINED ${PROJECT_NAME}) - project(Kokkos CXX) + PROJECT(Kokkos CXX) ENDIF() +ENDIF() - # Basic initialization (Used in KOKKOS_SETTINGS) - set(KOKKOS_SRC_PATH ${Kokkos_SOURCE_DIR}) - set(KOKKOS_PATH ${KOKKOS_SRC_PATH}) - - #------------ COMPILER AND FEATURE CHECKS ------------------------------------ - include(${KOKKOS_SRC_PATH}/cmake/kokkos_functions.cmake) - set_kokkos_cxx_compiler() - set_kokkos_cxx_standard() - - #------------ GET OPTIONS AND KOKKOS_SETTINGS -------------------------------- - # Add Kokkos' modules to CMake's module path. - set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Kokkos_SOURCE_DIR}/cmake/Modules/") - - set(KOKKOS_CMAKE_VERBOSE True) - include(${KOKKOS_SRC_PATH}/cmake/kokkos_options.cmake) - - include(${KOKKOS_SRC_PATH}/cmake/kokkos_settings.cmake) - - #------------ GENERATE HEADER AND SOURCE FILES ------------------------------- - execute_process( - COMMAND ${KOKKOS_SETTINGS} make -f ${KOKKOS_SRC_PATH}/cmake/Makefile.generate_cmake_settings CXX=${CMAKE_CXX_COMPILER} PREFIX=${CMAKE_INSTALL_PREFIX} generate_build_settings - WORKING_DIRECTORY "${Kokkos_BINARY_DIR}" - OUTPUT_FILE ${Kokkos_BINARY_DIR}/core_src_make.out - RESULT_VARIABLE GEN_SETTINGS_RESULT - ) - if (GEN_SETTINGS_RESULT) - message(FATAL_ERROR "Kokkos settings generation failed:\n" - "${KOKKOS_SETTINGS} make -f ${KOKKOS_SRC_PATH}/cmake/Makefile.generate_cmake_settings CXX=${CMAKE_CXX_COMPILER} generate_build_settings") - endif() - include(${Kokkos_BINARY_DIR}/kokkos_generated_settings.cmake) - install(FILES ${Kokkos_BINARY_DIR}/kokkos_generated_settings.cmake DESTINATION lib/cmake/Kokkos) - install(FILES ${Kokkos_BINARY_DIR}/kokkos_generated_settings.cmake DESTINATION ${CMAKE_INSTALL_PREFIX}) - string(REPLACE " " ";" KOKKOS_TPL_INCLUDE_DIRS "${KOKKOS_GMAKE_TPL_INCLUDE_DIRS}") - string(REPLACE " " ";" KOKKOS_TPL_LIBRARY_DIRS "${KOKKOS_GMAKE_TPL_LIBRARY_DIRS}") - string(REPLACE " " ";" KOKKOS_TPL_LIBRARY_NAMES "${KOKKOS_GMAKE_TPL_LIBRARY_NAMES}") - list(REMOVE_ITEM KOKKOS_TPL_INCLUDE_DIRS "") - list(REMOVE_ITEM KOKKOS_TPL_LIBRARY_DIRS "") - list(REMOVE_ITEM KOKKOS_TPL_LIBRARY_NAMES "") - set_kokkos_srcs(KOKKOS_SRC ${KOKKOS_SRC}) - - #------------ NOW BUILD ------------------------------------------------------ - include(${KOKKOS_SRC_PATH}/cmake/kokkos_build.cmake) - - #------------ Add in Fake Tribits Handling to allow unit test builds- -------- - - include(${KOKKOS_SRC_PATH}/cmake/tribits.cmake) - - TRIBITS_PACKAGE_DECL(Kokkos) - - ADD_SUBDIRECTORY(core) - ADD_SUBDIRECTORY(containers) - ADD_SUBDIRECTORY(algorithms) +IF (NOT CMAKE_SIZEOF_VOID_P) + STRING(FIND ${CMAKE_CXX_COMPILER} nvcc_wrapper FIND_IDX) + IF (NOT FIND_IDX STREQUAL -1) + MESSAGE(FATAL_ERROR "Kokkos did not configure correctly and failed to validate compiler. The most likely cause is CUDA linkage using nvcc_wrapper. Please ensure your CUDA environment is correctly configured.") + ELSE() + MESSAGE(FATAL_ERROR "Kokkos did not configure correctly and failed to validate compiler. The most likely cause is linkage errors during CMake compiler validation. Please consult the CMake error log shown below for the exact error during compiler validation") + ENDIF() +ELSEIF (NOT CMAKE_SIZEOF_VOID_P EQUAL 8) + MESSAGE(FATAL_ERROR "Kokkos assumes a 64-bit build; i.e., 8-byte pointers, but found ${CMAKE_SIZEOF_VOID_P}-byte pointers instead") +ENDIF() -ELSE() -#------------------------------------------------------------------------------ -# -# A) Forward declare the package so that certain options are also defined for -# subpackages -# -TRIBITS_PACKAGE_DECL(Kokkos) # ENABLE_SHADOWING_WARNINGS) +set(Kokkos_VERSION_MAJOR 3) +set(Kokkos_VERSION_MINOR 0) +set(Kokkos_VERSION_PATCH 0) +set(Kokkos_VERSION "${Kokkos_VERSION_MAJOR}.${Kokkos_VERSION_MINOR}.${Kokkos_VERSION_PATCH}") +IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + MESSAGE(STATUS "Setting policy CMP0074 to use _ROOT variables") + CMAKE_POLICY(SET CMP0074 NEW) +ENDIF() + +# Load either the real TriBITS or a TriBITS wrapper +# for certain utility functions that are universal (like GLOBAL_SET) +INCLUDE(${KOKKOS_SRC_PATH}/cmake/fake_tribits.cmake) + +IF (Kokkos_ENABLE_CUDA AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") + #If we are building CUDA, we have tricked CMake because we declare a CXX project + #If the default C++ standard for a given compiler matches the requested + #standard, then CMake just omits the -std flag in later versions of CMake + #This breaks CUDA compilation (CUDA compiler can have a different default + #-std then the underlying host compiler by itself). Setting this variable + #forces CMake to always add the -std flag even if it thinks it doesn't need it + GLOBAL_SET(CMAKE_CXX_STANDARD_DEFAULT 98) +ENDIF() + +# These are the variables we will append to as we go +# I really wish these were regular variables +# but scoping issues can make it difficult +GLOBAL_RESET(KOKKOS_COMPILE_OPTIONS) +GLOBAL_RESET(KOKKOS_LINK_OPTIONS) +GLOBAL_RESET(KOKKOS_CUDA_OPTIONS) +GLOBAL_RESET(KOKKOS_CUDAFE_OPTIONS) +GLOBAL_RESET(KOKKOS_XCOMPILER_OPTIONS) +# We need to append text here for making sure TPLs +# we import are available for an installed Kokkos +GLOBAL_RESET(KOKKOS_TPL_EXPORTS) +# We need these for controlling the exact -std flag +GLOBAL_RESET(KOKKOS_DONT_ALLOW_EXTENSIONS) +GLOBAL_RESET(KOKKOS_USE_CXX_EXTENSIONS) +GLOBAL_RESET(KOKKOS_CXX_STANDARD_FEATURE) + +# Include a set of Kokkos-specific wrapper functions that +# will either call raw CMake or TriBITS +# These are functions like KOKKOS_INCLUDE_DIRECTORIES +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_tribits.cmake) + + +# The build environment setup goes in the following steps +# 1) Check all the enable options. This includes checking Kokkos_DEVICES +# 2) Check the compiler ID (type and version) +# 3) Check the CXX standard and select important CXX flags +# 4) Check for any third-party libraries (TPLs) like hwloc +# 5) Check if optimizing for a particular architecture and add arch-specific flags +KOKKOS_SETUP_BUILD_ENVIRONMENT() + +# Finish off the build +# 6) Recurse into subdirectories and configure individual libraries +# 7) Export and install targets + +OPTION(BUILD_SHARED_LIBS "Build shared libraries" OFF) +# Workaround for building position independent code. +IF(BUILD_SHARED_LIBS) + SET(CMAKE_POSITION_INDEPENDENT_CODE ON) +ENDIF() + +SET(KOKKOS_EXT_LIBRARIES Kokkos::kokkos Kokkos::kokkoscore Kokkos::kokkoscontainers Kokkos::kokkosalgorithms) +SET(KOKKOS_INT_LIBRARIES kokkos kokkoscore kokkoscontainers kokkosalgorithms) +SET_PROPERTY(GLOBAL PROPERTY KOKKOS_INT_LIBRARIES ${KOKKOS_INT_LIBRARIES}) + +GET_DIRECTORY_PROPERTY(HAS_PARENT PARENT_DIRECTORY) +IF (KOKKOS_HAS_TRILINOS) + SET(TRILINOS_INCDIR ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}) + SET(KOKKOS_HEADER_DIR ${TRILINOS_INCDIR}) + SET(KOKKOS_IS_SUBDIRECTORY TRUE) +ELSEIF(HAS_PARENT) + SET(KOKKOS_HEADER_DIR "include/kokkos") + SET(KOKKOS_IS_SUBDIRECTORY TRUE) +ELSE() + SET(KOKKOS_HEADER_DIR "${CMAKE_INSTALL_INCLUDEDIR}") + SET(KOKKOS_IS_SUBDIRECTORY FALSE) +ENDIF() -#------------------------------------------------------------------------------ -# -# B) Install Kokkos' build files -# -# If using the Makefile-generated files, then need to set things up. -# Here, assume that TriBITS has been run from ProjectCompilerPostConfig.cmake -# and already generated KokkosCore_config.h and kokkos_generated_settings.cmake -# in the previously define Kokkos_GEN_DIR -# We need to copy them over to the correct place and source the cmake file - -if(NOT KOKKOS_LEGACY_TRIBITS) - set(Kokkos_GEN_DIR ${CMAKE_BINARY_DIR}) - file(COPY "${Kokkos_GEN_DIR}/KokkosCore_config.h" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" USE_SOURCE_PERMISSIONS) - install(FILES "${Kokkos_GEN_DIR}/KokkosCore_config.h" - DESTINATION include) - file(COPY "${Kokkos_GEN_DIR}/kokkos_generated_settings.cmake" - DESTINATION "${CMAKE_CURRENT_BINARY_DIR}" USE_SOURCE_PERMISSIONS) - - include(${CMAKE_CURRENT_BINARY_DIR}/kokkos_generated_settings.cmake) - # Sources come from makefile-generated kokkos_generated_settings.cmake file - # Enable using the individual sources if needed - set_kokkos_srcs(KOKKOS_SRC ${KOKKOS_SRC}) -endif () #------------------------------------------------------------------------------ # -# C) Install Kokkos' executable scripts -# +# A) Forward declare the package so that certain options are also defined for +# subpackages -# nvcc_wrapper is Kokkos' wrapper for NVIDIA's NVCC CUDA compiler. -# Kokkos needs nvcc_wrapper in order to build. Other libraries and -# executables also need nvcc_wrapper. Thus, we need to install it. -# If the argument of DESTINATION is a relative path, CMake computes it -# as relative to ${CMAKE_INSTALL_PATH}. +## This restores the old behavior of ProjectCompilerPostConfig.cmake +# It sets the CMAKE_CXX_FLAGS globally to those used by Kokkos +# We must do this before KOKKOS_PACKAGE_DECL +IF (KOKKOS_HAS_TRILINOS) + # Overwrite the old flags at the top-level + # Because Tribits doesn't use lists, it uses spaces for the list of CXX flags + # we have to match the annoying behavior + STRING(REPLACE ";" " " KOKKOSCORE_COMPILE_OPTIONS "${KOKKOS_COMPILE_OPTIONS}") + STRING(REPLACE ";" " " KOKKOSCORE_CUDA_OPTIONS "${KOKKOS_CUDA_OPTIONS}") + FOREACH(CUDAFE_FLAG ${KOKKOS_CUDAFE_OPTIONS}) + SET(KOKKOSCORE_CUDAFE_OPTIONS "${KOKKOSCORE_CUDAFE_OPTIONS} -Xcudafe ${CUDAFE_FLAG}") + ENDFOREACH() + FOREACH(XCOMP_FLAG ${KOKKOS_XCOMPILER_OPTIONS}) + SET(KOKKOSCORE_XCOMPILER_OPTIONS "${KOKKOSCORE_XCOMPILER_OPTIONS} -Xcompiler ${XCOMP_FLAG}") + ENDFOREACH() + SET(KOKKOSCORE_CXX_FLAGS "${KOKKOSCORE_COMPILE_OPTIONS} ${CMAKE_CXX${KOKKOS_CXX_STANDARD}_STANDARD_COMPILE_OPTION} ${KOKKOSCORE_CUDA_OPTIONS} ${KOKKOSCORE_CUDAFE_OPTIONS} ${KOKKOSCORE_XCOMPILER_OPTIONS}") + # Both parent scope and this package + # In ProjectCompilerPostConfig.cmake, we capture the "global" flags Trilinos wants in + # TRILINOS_TOPLEVEL_CXX_FLAGS + SET(CMAKE_CXX_FLAGS "${TRILINOS_TOPLEVEL_CXX_FLAGS} ${KOKKOSCORE_CXX_FLAGS}" PARENT_SCOPE) + SET(CMAKE_CXX_FLAGS "${TRILINOS_TOPLEVEL_CXX_FLAGS} ${KOKKOSCORE_CXX_FLAGS}") + #CMAKE_CXX_FLAGS will get added to Kokkos and Kokkos dependencies automatically here + #These flags get set up in KOKKOS_PACKAGE_DECL, which means they + #must be configured before KOKKOS_PACKAGE_DECL +ENDIF() -INSTALL(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/bin/nvcc_wrapper DESTINATION bin) +KOKKOS_PACKAGE_DECL() #------------------------------------------------------------------------------ # -# D) Process the subpackages for Kokkos +# D) Process the subpackages (subdirectories) for Kokkos # - -TRIBITS_PROCESS_SUBPACKAGES() +KOKKOS_PROCESS_SUBPACKAGES() #------------------------------------------------------------------------------ @@ -130,10 +220,39 @@ TRIBITS_PROCESS_SUBPACKAGES() # E) If Kokkos itself is enabled, process the Kokkos package # -TRIBITS_PACKAGE_DEF() +KOKKOS_PACKAGE_DEF() +KOKKOS_EXCLUDE_AUTOTOOLS_FILES() +KOKKOS_PACKAGE_POSTPROCESS() -TRIBITS_EXCLUDE_AUTOTOOLS_FILES() +#We are ready to configure the header +CONFIGURE_FILE(cmake/KokkosCore_config.h.in KokkosCore_config.h @ONLY) -TRIBITS_PACKAGE_POSTPROCESS() +IF (NOT KOKKOS_HAS_TRILINOS) + ADD_LIBRARY(kokkos INTERFACE) + #Make sure in-tree projects can reference this as Kokkos:: + #to match the installed target names + ADD_LIBRARY(Kokkos::kokkos ALIAS kokkos) + TARGET_LINK_LIBRARIES(kokkos INTERFACE kokkoscore kokkoscontainers kokkosalgorithms) + KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL(kokkos) +ENDIF() +INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_install.cmake) +# nvcc_wrapper is Kokkos' wrapper for NVIDIA's NVCC CUDA compiler. +# Kokkos needs nvcc_wrapper in order to build. Other libraries and +# executables also need nvcc_wrapper. Thus, we need to install it. +# If the argument of DESTINATION is a relative path, CMake computes it +# as relative to ${CMAKE_INSTALL_PATH}. +INSTALL(PROGRAMS ${CMAKE_CURRENT_SOURCE_DIR}/bin/nvcc_wrapper DESTINATION ${CMAKE_INSTALL_BINDIR}) +INSTALL(FILES "${CMAKE_CURRENT_BINARY_DIR}/KokkosCore_config.h" DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) + + +# Finally - if we are a subproject - make sure the enabled devices are visible +IF (HAS_PARENT) + FOREACH(DEV Kokkos_ENABLED_DEVICES) + #I would much rather not make these cache variables or global properties, but I can't + #make any guarantees on whether PARENT_SCOPE is good enough to make + #these variables visible where I need them + SET(Kokkos_ENABLE_${DEV} ON PARENT_SCOPE) + SET_PROPERTY(GLOBAL PROPERTY Kokkos_ENABLE_${DEV} ON) + ENDFOREACH() ENDIF() diff --git a/lib/kokkos/CONTRIBUTING.md b/lib/kokkos/CONTRIBUTING.md new file mode 100644 index 0000000000..b4f3057cef --- /dev/null +++ b/lib/kokkos/CONTRIBUTING.md @@ -0,0 +1,14 @@ +# Contributing to Kokkos + +## Pull Requests +We actively welcome pull requests. +1. Fork the repo and create your branch from `develop`. +2. If you've added code that should be tested, add tests. +3. If you've changed APIs, update the documentation. +4. Ensure the test suite passes. + +## Issues +We use GitHub issues to track public bugs. Please ensure your description is clear and has sufficient instructions to be able to reproduce the issue. + +## License +By contributing to Kokkos, you agree that your contributions will be licensed under the LICENSE file in the root directory of this source tree. diff --git a/lib/kokkos/Copyright.txt b/lib/kokkos/Copyright.txt index 50b76995af..06184796b2 100644 --- a/lib/kokkos/Copyright.txt +++ b/lib/kokkos/Copyright.txt @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/LICENSE b/lib/kokkos/LICENSE index c68a8a2a9f..c6f17087d5 100644 --- a/lib/kokkos/LICENSE +++ b/lib/kokkos/LICENSE @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Kokkos is licensed under 3-clause BSD terms of use: @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/Makefile.kokkos b/lib/kokkos/Makefile.kokkos index e9ad57f0ae..fd96e14bb5 100644 --- a/lib/kokkos/Makefile.kokkos +++ b/lib/kokkos/Makefile.kokkos @@ -23,14 +23,16 @@ KOKKOS_DEBUG ?= "no" KOKKOS_USE_TPLS ?= "" # Options: c++11,c++14,c++1y,c++17,c++1z,c++2a KOKKOS_CXX_STANDARD ?= "c++11" -# Options: aggressive_vectorization,disable_profiling,enable_deprecated_code,disable_deprecated_code,enable_large_mem_tests +# Options: aggressive_vectorization,disable_profiling,enable_deprecated_code,disable_deprecated_code,enable_large_mem_tests,disable_complex_align KOKKOS_OPTIONS ?= "" # Option for setting ETI path KOKKOS_ETI_PATH ?= ${KOKKOS_PATH}/core/src/eti KOKKOS_CMAKE ?= "no" +KOKKOS_TRIBITS ?= "no" +KOKKOS_STANDALONE_CMAKE ?= "no" # Default settings specific options. -# Options: force_uvm,use_ldg,rdc,enable_lambda +# Options: force_uvm,use_ldg,rdc,enable_lambda,enable_constexpr KOKKOS_CUDA_OPTIONS ?= "enable_lambda" # Default settings specific options. @@ -47,7 +49,8 @@ kokkos_has_string=$(if $(findstring $2,$1),1,0) # Will return a 1 if /path/to/file exists kokkos_path_exists=$(if $(wildcard $1),1,0) -# Check for general settings. +# Check for general settings + KOKKOS_INTERNAL_ENABLE_DEBUG := $(call kokkos_has_string,$(KOKKOS_DEBUG),yes) KOKKOS_INTERNAL_ENABLE_CXX11 := $(call kokkos_has_string,$(KOKKOS_CXX_STANDARD),c++11) KOKKOS_INTERNAL_ENABLE_CXX14 := $(call kokkos_has_string,$(KOKKOS_CXX_STANDARD),c++14) @@ -67,6 +70,7 @@ KOKKOS_INTERNAL_OPT_RANGE_AGGRESSIVE_VECTORIZATION := $(call kokkos_has_string,$ KOKKOS_INTERNAL_DISABLE_PROFILING := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_profiling) KOKKOS_INTERNAL_DISABLE_DEPRECATED_CODE := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_deprecated_code) KOKKOS_INTERNAL_ENABLE_DEPRECATED_CODE := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_deprecated_code) +KOKKOS_INTERNAL_DISABLE_COMPLEX_ALIGN := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_complex_align) KOKKOS_INTERNAL_DISABLE_DUALVIEW_MODIFY_CHECK := $(call kokkos_has_string,$(KOKKOS_OPTIONS),disable_dualview_modify_check) KOKKOS_INTERNAL_ENABLE_PROFILING_LOAD_PRINT := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_profile_load_print) KOKKOS_INTERNAL_ENABLE_LARGE_MEM_TESTS := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_large_mem_tests) @@ -74,6 +78,7 @@ KOKKOS_INTERNAL_CUDA_USE_LDG := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS), KOKKOS_INTERNAL_CUDA_USE_UVM := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),force_uvm) KOKKOS_INTERNAL_CUDA_USE_RELOC := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),rdc) KOKKOS_INTERNAL_CUDA_USE_LAMBDA := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),enable_lambda) +KOKKOS_INTERNAL_CUDA_USE_CONSTEXPR := $(call kokkos_has_string,$(KOKKOS_CUDA_OPTIONS),enable_constexpr) KOKKOS_INTERNAL_HPX_ENABLE_ASYNC_DISPATCH := $(call kokkos_has_string,$(KOKKOS_HPX_OPTIONS),enable_async_dispatch) KOKKOS_INTERNAL_ENABLE_ETI := $(call kokkos_has_string,$(KOKKOS_OPTIONS),enable_eti) @@ -123,7 +128,7 @@ KOKKOS_INTERNAL_COMPILER_INTEL := $(call kokkos_has_string,$(KOKKOS_CXX_VE KOKKOS_INTERNAL_COMPILER_PGI := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),PGI) KOKKOS_INTERNAL_COMPILER_XL := $(strip $(shell $(CXX) -qversion 2>&1 | grep XL | wc -l)) KOKKOS_INTERNAL_COMPILER_CRAY := $(strip $(shell $(CXX) -craype-verbose 2>&1 | grep "CC-" | wc -l)) -KOKKOS_INTERNAL_COMPILER_NVCC := $(strip $(shell export OMPI_CXX=$(OMPI_CXX); export MPICH_CXX=$(MPICH_CXX); $(CXX) --version 2>&1 | grep nvcc | wc -l)) +KOKKOS_INTERNAL_COMPILER_NVCC := $(strip $(shell export OMPI_CXX=$(OMPI_CXX); export MPICH_CXX=$(MPICH_CXX); echo "$(shell $(CXX) --version 2>&1 | grep nvcc | wc -l)>0" | bc)) KOKKOS_INTERNAL_COMPILER_CLANG := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),clang) KOKKOS_INTERNAL_COMPILER_APPLE_CLANG := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),Apple LLVM) KOKKOS_INTERNAL_COMPILER_HCC := $(call kokkos_has_string,$(KOKKOS_CXX_VERSION),HCC) @@ -383,10 +388,10 @@ endif # Generating the list of Flags. -#CPPFLAGS is now unused KOKKOS_CPPFLAGS = +KOKKOS_LIBDIRS = ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS = -I./ -I$(KOKKOS_PATH)/core/src -I$(KOKKOS_PATH)/containers/src -I$(KOKKOS_PATH)/algorithms/src -I$(KOKKOS_ETI_PATH) + KOKKOS_CPPFLAGS = -I./ -I$(KOKKOS_PATH)/core/src -I$(KOKKOS_PATH)/containers/src -I$(KOKKOS_PATH)/algorithms/src -I$(KOKKOS_ETI_PATH) endif KOKKOS_TPL_INCLUDE_DIRS = KOKKOS_TPL_LIBRARY_DIRS = @@ -399,7 +404,7 @@ endif KOKKOS_LIBS = -ldl KOKKOS_TPL_LIBRARY_NAMES += dl ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_LDFLAGS = -L$(shell pwd) + KOKKOS_LIBDIRS = -L$(shell pwd) # CXXLDFLAGS is used together with CXXFLAGS in a combined compile/link command KOKKOS_CXXLDFLAGS = -L$(shell pwd) endif @@ -492,28 +497,38 @@ ifeq ($(KOKKOS_INTERNAL_USE_ISA_POWERPCBE), 1) tmp := $(call kokkos_append_header,"\#endif") endif +#only add the c++ standard flags if this is not CMake tmp := $(call kokkos_append_header,"/* General Settings */") ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX11), 1) +ifneq ($(KOKKOS_STANDALONE_CMAKE), yes) KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX11_FLAG) +endif tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX11") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX14), 1) +ifneq ($(KOKKOS_STANDALONE_CMAKE), yes) KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX14_FLAG) +endif tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX14") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX1Y), 1) + #I cannot make CMake add this in a good way - so add it here KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX1Y_FLAG) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX14") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX17), 1) +ifneq ($(KOKKOS_STANDALONE_CMAKE), yes) KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX17_FLAG) +endif tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX17") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX1Z), 1) + #I cannot make CMake add this in a good way - so add it here KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX1Z_FLAG) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX17") endif ifeq ($(KOKKOS_INTERNAL_ENABLE_CXX2A), 1) + #I cannot make CMake add this in a good way - so add it here KOKKOS_CXXFLAGS += $(KOKKOS_INTERNAL_CXX2A_FLAG) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CXX20") endif @@ -531,23 +546,26 @@ ifeq ($(KOKKOS_INTERNAL_ENABLE_DEBUG), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK") endif endif +ifeq ($(KOKKOS_INTERNAL_DISABLE_COMPLEX_ALIGN), 0) + tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_COMPLEX_ALIGN") +endif ifeq ($(KOKKOS_INTERNAL_ENABLE_PROFILING_LOAD_PRINT), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_PROFILING_LOAD_PRINT") endif ifeq ($(KOKKOS_INTERNAL_USE_HWLOC), 1) - ifneq ($(HWLOC_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(HWLOC_PATH)/include + ifneq ($(KOKKOS_CMAKE), yes) + ifneq ($(HWLOC_PATH),) + KOKKOS_CPPFLAGS += -I$(HWLOC_PATH)/include + KOKKOS_LIBDIRS += -L$(HWLOC_PATH)/lib + KOKKOS_CXXLDFLAGS += -L$(HWLOC_PATH)/lib + KOKKOS_TPL_INCLUDE_DIRS += $(HWLOC_PATH)/include + KOKKOS_TPL_LIBRARY_DIRS += $(HWLOC_PATH)/lib endif - KOKKOS_LDFLAGS += -L$(HWLOC_PATH)/lib - KOKKOS_CXXLDFLAGS += -L$(HWLOC_PATH)/lib - KOKKOS_TPL_INCLUDE_DIRS += $(HWLOC_PATH)/include - KOKKOS_TPL_LIBRARY_DIRS += $(HWLOC_PATH)/lib + KOKKOS_LIBS += -lhwloc + KOKKOS_TPL_LIBRARY_NAMES += hwloc endif - KOKKOS_LIBS += -lhwloc - KOKKOS_TPL_LIBRARY_NAMES += hwloc tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_HWLOC") endif @@ -558,17 +576,17 @@ ifeq ($(KOKKOS_INTERNAL_USE_LIBRT), 1) endif ifeq ($(KOKKOS_INTERNAL_USE_MEMKIND), 1) - ifneq ($(MEMKIND_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(MEMKIND_PATH)/include + ifneq ($(KOKKOS_CMAKE), yes) + ifneq ($(MEMKIND_PATH),) + KOKKOS_CPPFLAGS += -I$(MEMKIND_PATH)/include + KOKKOS_LIBDIRS += -L$(MEMKIND_PATH)/lib + KOKKOS_CXXLDFLAGS += -L$(MEMKIND_PATH)/lib + KOKKOS_TPL_INCLUDE_DIRS += $(MEMKIND_PATH)/include + KOKKOS_TPL_LIBRARY_DIRS += $(MEMKIND_PATH)/lib endif - KOKKOS_LDFLAGS += -L$(MEMKIND_PATH)/lib - KOKKOS_CXXLDFLAGS += -L$(MEMKIND_PATH)/lib - KOKKOS_TPL_INCLUDE_DIRS += $(MEMKIND_PATH)/include - KOKKOS_TPL_LIBRARY_DIRS += $(MEMKIND_PATH)/lib + KOKKOS_LIBS += -lmemkind -lnuma + KOKKOS_TPL_LIBRARY_NAMES += memkind numa endif - KOKKOS_LIBS += -lmemkind -lnuma - KOKKOS_TPL_LIBRARY_NAMES += memkind numa tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_HBWSPACE") endif @@ -580,9 +598,6 @@ ifeq ($(KOKKOS_INTERNAL_USE_HPX), 0) ifeq ($(KOKKOS_INTERNAL_ENABLE_DEPRECATED_CODE), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_DEPRECATED_CODE") endif - ifeq ($(KOKKOS_INTERNAL_DISABLE_DEPRECATED_CODE), 0) - tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_DEPRECATED_CODE") - endif endif ifeq ($(KOKKOS_INTERNAL_ENABLE_ETI), 1) @@ -648,6 +663,21 @@ ifeq ($(KOKKOS_INTERNAL_USE_CUDA), 1) endif endif + ifeq ($(KOKKOS_INTERNAL_CUDA_USE_CONSTEXPR), 1) + ifeq ($(KOKKOS_INTERNAL_COMPILER_NVCC), 1) + ifeq ($(shell test $(KOKKOS_INTERNAL_COMPILER_NVCC_VERSION) -ge 80; echo $$?),0) + tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CUDA_CONSTEXPR") + KOKKOS_CXXFLAGS += -expt-relaxed-constexpr + else + $(warning Warning: Cuda relaxed constexpr support was requested but NVCC version is too low. This requires NVCC for Cuda version 8.0 or higher. Disabling relaxed constexpr support now.) + endif + endif + + ifeq ($(KOKKOS_INTERNAL_COMPILER_CLANG), 1) + tmp := $(call kokkos_append_header,"\#define KOKKOS_ENABLE_CUDA_CONSTEXPR") + endif + endif + ifeq ($(KOKKOS_INTERNAL_COMPILER_CLANG), 1) tmp := $(call kokkos_append_header,"\#define KOKKOS_IMPL_CUDA_CLANG_WORKAROUND") endif @@ -1089,15 +1119,13 @@ ifeq ($(KOKKOS_INTERNAL_ENABLE_ETI), 1) endif KOKKOS_HEADERS += $(wildcard $(KOKKOS_PATH)/core/src/Cuda/*.hpp) ifneq ($(CUDA_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(CUDA_PATH)/include - endif + KOKKOS_CPPLAGS += -I$(CUDA_PATH)/include ifeq ($(call kokkos_path_exists,$(CUDA_PATH)/lib64), 1) - KOKKOS_LDFLAGS += -L$(CUDA_PATH)/lib64 + KOKKOS_LIBDIRS += -L$(CUDA_PATH)/lib64 KOKKOS_CXXLDFLAGS += -L$(CUDA_PATH)/lib64 KOKKOS_TPL_LIBRARY_DIRS += $(CUDA_PATH)/lib64 else ifeq ($(call kokkos_path_exists,$(CUDA_PATH)/lib), 1) - KOKKOS_LDFLAGS += -L$(CUDA_PATH)/lib + KOKKOS_LIBDIRS += -L$(CUDA_PATH)/lib KOKKOS_CXXLDFLAGS += -L$(CUDA_PATH)/lib KOKKOS_TPL_LIBRARY_DIRS += $(CUDA_PATH)/lib else @@ -1153,17 +1181,17 @@ endif ifeq ($(KOKKOS_INTERNAL_USE_QTHREADS), 1) KOKKOS_SRC += $(wildcard $(KOKKOS_PATH)/core/src/Qthreads/*.cpp) KOKKOS_HEADERS += $(wildcard $(KOKKOS_PATH)/core/src/Qthreads/*.hpp) - ifneq ($(QTHREADS_PATH),) - ifneq ($(KOKKOS_CMAKE), yes) - KOKKOS_CXXFLAGS += -I$(QTHREADS_PATH)/include + ifneq ($(KOKKOS_CMAKE), yes) + ifneq ($(QTHREADS_PATH),) + KOKKOS_CPPFLAGS += -I$(QTHREADS_PATH)/include + KOKKOS_LIBDIRS += -L$(QTHREADS_PATH)/lib + KOKKOS_CXXLDFLAGS += -L$(QTHREADS_PATH)/lib + KOKKOS_TPL_INCLUDE_DIRS += $(QTHREADS_PATH)/include + KOKKOS_TPL_LIBRARY_DIRS += $(QTHREADS_PATH)/lib64 endif - KOKKOS_LDFLAGS += -L$(QTHREADS_PATH)/lib - KOKKOS_CXXLDFLAGS += -L$(QTHREADS_PATH)/lib - KOKKOS_TPL_INCLUDE_DIRS += $(QTHREADS_PATH)/include - KOKKOS_TPL_LIBRARY_DIRS += $(QTHREADS_PATH)/lib64 + KOKKOS_LIBS += -lqthread + KOKKOS_TPL_LIBRARY_NAMES += qthread endif - KOKKOS_LIBS += -lqthread - KOKKOS_TPL_LIBRARY_NAMES += qthread endif ifeq ($(KOKKOS_INTERNAL_USE_HPX), 1) @@ -1173,21 +1201,21 @@ ifeq ($(KOKKOS_INTERNAL_USE_HPX), 1) ifeq ($(KOKKOS_INTERNAL_ENABLE_DEBUG), 1) KOKKOS_CXXFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --cflags hpx_application_debug) KOKKOS_CXXLDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application_debug) - KOKKOS_LDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application_debug) + KOKKOS_LIBS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application_debug) else KOKKOS_CXXFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --cflags hpx_application) KOKKOS_CXXLDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application) - KOKKOS_LDFLAGS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application) + KOKKOS_LIBS += $(shell PKG_CONFIG_PATH=$(HPX_PATH)/lib64/pkgconfig pkg-config --libs hpx_application) endif else ifeq ($(KOKKOS_INTERNAL_ENABLE_DEBUG), 1) KOKKOS_CXXFLAGS += $(shell pkg-config --cflags hpx_application_debug) KOKKOS_CXXLDFLAGS += $(shell pkg-config --libs hpx_application_debug) - KOKKOS_LDFLAGS += $(shell pkg-config --libs hpx_application_debug) + KOKKOS_LIBS += $(shell pkg-config --libs hpx_application_debug) else KOKKOS_CXXFLAGS += $(shell pkg-config --cflags hpx_application) KOKKOS_CXXLDFLAGS += $(shell pkg-config --libs hpx_application) - KOKKOS_LDFLAGS += $(shell pkg-config --libs hpx_application) + KOKKOS_LIBS += $(shell pkg-config --libs hpx_application) endif endif KOKKOS_TPL_LIBRARY_NAMES += hpx @@ -1248,4 +1276,16 @@ libkokkos.a: $(KOKKOS_OBJ_LINK) $(KOKKOS_SRC) $(KOKKOS_HEADERS) ar cr libkokkos.a $(KOKKOS_OBJ_LINK) ranlib libkokkos.a +print-cxx-flags: + echo "$(KOKKOS_CXXFLAGS)" + KOKKOS_LINK_DEPENDS=libkokkos.a + +#we have carefully separated LDFLAGS from LIBS and LIBDIRS +#we have also separated CPPFLAGS from CXXFLAGS +#if this is not cmake, for backwards compatibility +#we just jam everything together into the CXXFLAGS and LDFLAGS +ifneq ($(KOKKOS_CMAKE), yes) + KOKKOS_CXXFLAGS += $(KOKKOS_CPPFLAGS) + KOKKOS_LDFLAGS += $(KOKKOS_LIBDIRS) +endif diff --git a/lib/kokkos/Makefile.targets b/lib/kokkos/Makefile.targets index e7d5a3c907..0a1f522016 100644 --- a/lib/kokkos/Makefile.targets +++ b/lib/kokkos/Makefile.targets @@ -6,6 +6,8 @@ Kokkos_CPUDiscovery.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_CPUDiscovery.cpp Kokkos_Error.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Error.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Error.cpp +Kokkos_Stacktrace.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_Stacktrace.cpp + $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_Stacktrace.cpp Kokkos_ExecPolicy.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_ExecPolicy.cpp $(CXX) $(KOKKOS_CPPFLAGS) $(KOKKOS_CXXFLAGS) $(CXXFLAGS) -c $(KOKKOS_PATH)/core/src/impl/Kokkos_ExecPolicy.cpp Kokkos_HostSpace.o: $(KOKKOS_CPP_DEPENDS) $(KOKKOS_PATH)/core/src/impl/Kokkos_HostSpace.cpp diff --git a/lib/kokkos/README b/lib/kokkos/README deleted file mode 100644 index cb6ceb5581..0000000000 --- a/lib/kokkos/README +++ /dev/null @@ -1,193 +0,0 @@ -Kokkos Core implements a programming model in C++ for writing performance portable -applications targeting all major HPC platforms. For that purpose it provides -abstractions for both parallel execution of code and data management. -Kokkos is designed to target complex node architectures with N-level memory -hierarchies and multiple types of execution resources. It currently can use -OpenMP, Pthreads and CUDA as backend programming models. - -Kokkos Core is part of the Kokkos C++ Performance Portability Programming EcoSystem, -which also provides math kernels (https://github.com/kokkos/kokkos-kernels), as well as -profiling and debugging tools (https://github.com/kokkos/kokkos-tools). - -# Learning about Kokkos - -A programming guide can be found on the Wiki, the API reference is under development. - -For questions find us on Slack: https://kokkosteam.slack.com or open a github issue. - -For non-public questions send an email to -crtrott(at)sandia.gov - -A separate repository with extensive tutorial material can be found under -https://github.com/kokkos/kokkos-tutorials. - -Furthermore, the 'example/tutorial' directory provides step by step tutorial -examples which explain many of the features of Kokkos. They work with -simple Makefiles. To build with g++ and OpenMP simply type 'make' -in the 'example/tutorial' directory. This will build all examples in the -subfolders. To change the build options refer to the Programming Guide -in the compilation section. - -To learn more about Kokkos consider watching one of our presentations: -* GTC 2015: - - http://on-demand.gputechconf.com/gtc/2015/video/S5166.html - - http://on-demand.gputechconf.com/gtc/2015/presentation/S5166-H-Carter-Edwards.pdf - - -# Contributing to Kokkos - -We are open and try to encourage contributions from external developers. -To do so please first open an issue describing the contribution and then issue -a pull request against the develop branch. For larger features it may be good -to get guidance from the core development team first through the github issue. - -Note that Kokkos Core is licensed under standard 3-clause BSD terms of use. -Which means contributing to Kokkos allows anyone else to use your contributions -not just for public purposes but also for closed source commercial projects. -For specifics see the LICENSE file contained in the repository or distribution. - -# Requirements - -### Primary tested compilers on X86 are: - * GCC 4.8.4 - * GCC 4.9.3 - * GCC 5.1.0 - * GCC 5.5.0 - * GCC 6.1.0 - * GCC 7.2.0 - * GCC 7.3.0 - * GCC 8.1.0 - * Intel 15.0.2 - * Intel 16.0.1 - * Intel 17.0.1 - * Intel 17.4.196 - * Intel 18.2.128 - * Clang 3.6.1 - * Clang 3.7.1 - * Clang 3.8.1 - * Clang 3.9.0 - * Clang 4.0.0 - * Clang 6.0.0 for CUDA (CUDA Toolkit 9.0) - * Clang 7.0.0 for CUDA (CUDA Toolkit 9.1) - * PGI 18.7 - * NVCC 7.5 for CUDA (with gcc 4.8.4) - * NVCC 8.0.44 for CUDA (with gcc 5.3.0) - * NVCC 9.1 for CUDA (with gcc 6.1.0) - * NVCC 9.2 for CUDA (with gcc 7.2.0) - * NVCC 10.0 for CUDA (with gcc 7.4.0) - -### Primary tested compilers on Power 8 are: - * GCC 6.4.0 (OpenMP,Serial) - * GCC 7.2.0 (OpenMP,Serial) - * IBM XL 16.1.0 (OpenMP, Serial) - * NVCC 9.2.88 for CUDA (with gcc 7.2.0 and XL 16.1.0) - -### Primary tested compilers on Intel KNL are: - * Intel 16.4.258 (with gcc 4.7.2) - * Intel 17.2.174 (with gcc 4.9.3) - * Intel 18.2.199 (with gcc 4.9.3) - -### Primary tested compilers on ARM (Cavium ThunderX2) - * GCC 7.2.0 - * ARM/Clang 18.4.0 - -### Other compilers working: - * X86: - - Cygwin 2.1.0 64bit with gcc 4.9.3 - - GCC 8.1.0 (not warning free) - -### Known non-working combinations: - * Power8: - - Pthreads backend - * ARM - - Pthreads backend - - -Primary tested compiler are passing in release mode -with warnings as errors. They also are tested with a comprehensive set of -backend combinations (i.e. OpenMP, Pthreads, Serial, OpenMP+Serial, ...). -We are using the following set of flags: -GCC: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits - -Wignored-qualifiers -Wempty-body -Wclobbered -Wuninitialized -Intel: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits -Wuninitialized -Clang: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits -Wuninitialized -NVCC: -Wall -Wshadow -pedantic -Werror -Wsign-compare -Wtype-limits -Wuninitialized - -Other compilers are tested occasionally, in particular when pushing from develop to -master branch, without -Werror and only for a select set of backends. - -# Running Unit Tests - -To run the unit tests create a build directory and run the following commands - -KOKKOS_PATH/generate_makefile.bash -make build-test -make test - -Run KOKKOS_PATH/generate_makefile.bash --help for more detailed options such as -changing the device type for which to build. - -# Installing the library - -To install Kokkos as a library create a build directory and run the following - -KOKKOS_PATH/generate_makefile.bash --prefix=INSTALL_PATH -make kokkoslib -make install - -KOKKOS_PATH/generate_makefile.bash --help for more detailed options such as -changing the device type for which to build. - -Note that in many cases it is preferable to build Kokkos inline with an -application. The main reason is that you may otherwise need many different -configurations of Kokkos installed depending on the required compile time -features an application needs. For example there is only one default -execution space, which means you need different installations to have OpenMP -or Pthreads as the default space. Also for the CUDA backend there are certain -choices, such as allowing relocatable device code, which must be made at -installation time. Building Kokkos inline uses largely the same process -as compiling an application against an installed Kokkos library. See for -example benchmarks/bytes_and_flops/Makefile which can be used with an installed -library and for an inline build. - -### CMake - -Kokkos supports being build as part of a CMake applications. An example can -be found in example/cmake_build. - -# Kokkos and CUDA UVM - -Kokkos does support UVM as a specific memory space called CudaUVMSpace. -Allocations made with that space are accessible from host and device. -You can tell Kokkos to use that as the default space for Cuda allocations. -In either case UVM comes with a number of restrictions: -(i) You can't access allocations on the host while a kernel is potentially -running. This will lead to segfaults. To avoid that you either need to -call Kokkos::Cuda::fence() (or just Kokkos::fence()), after kernels, or -you can set the environment variable CUDA_LAUNCH_BLOCKING=1. -Furthermore in multi socket multi GPU machines without NVLINK, UVM defaults -to using zero copy allocations for technical reasons related to using multiple -GPUs from the same process. If an executable doesn't do that (e.g. each -MPI rank of an application uses a single GPU [can be the same GPU for -multiple MPI ranks]) you can set CUDA_MANAGED_FORCE_DEVICE_ALLOC=1. -This will enforce proper UVM allocations, but can lead to errors if -more than a single GPU is used by a single process. - - -# Citing Kokkos - -If you publish work which mentions Kokkos, please cite the following paper: - -@article{CarterEdwards20143202, -title = "Kokkos: Enabling manycore performance portability through polymorphic memory access patterns ", -journal = "Journal of Parallel and Distributed Computing ", -volume = "74", -number = "12", -pages = "3202 - 3216", -year = "2014", -note = "Domain-Specific Languages and High-Level Frameworks for High-Performance Computing ", -issn = "0743-7315", -doi = "https://doi.org/10.1016/j.jpdc.2014.07.003", -url = "http://www.sciencedirect.com/science/article/pii/S0743731514001257", -author = "H. Carter Edwards and Christian R. Trott and Daniel Sunderland" -} diff --git a/lib/kokkos/README.md b/lib/kokkos/README.md new file mode 100644 index 0000000000..322dabfdab --- /dev/null +++ b/lib/kokkos/README.md @@ -0,0 +1,299 @@ +![Kokkos](https://avatars2.githubusercontent.com/u/10199860?s=200&v=4) + +# Kokkos: Core Libraries + +Kokkos Core implements a programming model in C++ for writing performance portable +applications targeting all major HPC platforms. For that purpose it provides +abstractions for both parallel execution of code and data management. +Kokkos is designed to target complex node architectures with N-level memory +hierarchies and multiple types of execution resources. It currently can use +CUDA, HPX, OpenMP and Pthreads as backend programming models with several other +backends in development. + +Kokkos Core is part of the Kokkos C++ Performance Portability Programming EcoSystem, +which also provides math kernels (https://github.com/kokkos/kokkos-kernels), as well as +profiling and debugging tools (https://github.com/kokkos/kokkos-tools). + +# Learning about Kokkos + +A programming guide can be found on the Wiki, the API reference is under development. + +For questions find us on Slack: https://kokkosteam.slack.com or open a github issue. + +For non-public questions send an email to +crtrott(at)sandia.gov + +A separate repository with extensive tutorial material can be found under +https://github.com/kokkos/kokkos-tutorials. + +Furthermore, the 'example/tutorial' directory provides step by step tutorial +examples which explain many of the features of Kokkos. They work with +simple Makefiles. To build with g++ and OpenMP simply type 'make' +in the 'example/tutorial' directory. This will build all examples in the +subfolders. To change the build options refer to the Programming Guide +in the compilation section. + +To learn more about Kokkos consider watching one of our presentations: +* GTC 2015: + - http://on-demand.gputechconf.com/gtc/2015/video/S5166.html + - http://on-demand.gputechconf.com/gtc/2015/presentation/S5166-H-Carter-Edwards.pdf + + +# Contributing to Kokkos + +We are open and try to encourage contributions from external developers. +To do so please first open an issue describing the contribution and then issue +a pull request against the develop branch. For larger features it may be good +to get guidance from the core development team first through the github issue. + +Note that Kokkos Core is licensed under standard 3-clause BSD terms of use. +Which means contributing to Kokkos allows anyone else to use your contributions +not just for public purposes but also for closed source commercial projects. +For specifics see the LICENSE file contained in the repository or distribution. + +# Requirements + +### Primary tested compilers on X86 are: +* GCC 4.8.4 +* GCC 4.9.3 +* GCC 5.1.0 +* GCC 5.4.0 +* GCC 5.5.0 +* GCC 6.1.0 +* GCC 7.2.0 +* GCC 7.3.0 +* GCC 8.1.0 +* Intel 15.0.2 +* Intel 16.0.1 +* Intel 17.0.1 +* Intel 17.4.196 +* Intel 18.2.128 +* Clang 3.6.1 +* Clang 3.7.1 +* Clang 3.8.1 +* Clang 3.9.0 +* Clang 4.0.0 +* Clang 6.0.0 for CUDA (CUDA Toolkit 9.0) +* Clang 7.0.0 for CUDA (CUDA Toolkit 9.1) +* Clang 8.0.0 for CUDA (CUDA Toolkit 9.2) +* PGI 18.7 +* NVCC 9.1 for CUDA (with gcc 6.1.0) +* NVCC 9.2 for CUDA (with gcc 7.2.0) +* NVCC 10.0 for CUDA (with gcc 7.4.0) +* NVCC 10.1 for CUDA (with gcc 7.4.0) + +### Primary tested compilers on Power 8 are: +* GCC 6.4.0 (OpenMP,Serial) +* GCC 7.2.0 (OpenMP,Serial) +* IBM XL 16.1.0 (OpenMP, Serial) +* NVCC 9.2.88 for CUDA (with gcc 7.2.0 and XL 16.1.0) + +### Primary tested compilers on Intel KNL are: +* Intel 16.4.258 (with gcc 4.7.2) +* Intel 17.2.174 (with gcc 4.9.3) +* Intel 18.2.199 (with gcc 4.9.3) + +### Primary tested compilers on ARM (Cavium ThunderX2) +* GCC 7.2.0 +* ARM/Clang 18.4.0 + +### Other compilers working: +* X86: + * Cygwin 2.1.0 64bit with gcc 4.9.3 + * GCC 8.1.0 (not warning free) + +### Known non-working combinations: +* Power8: + * Pthreads backend +* ARM + * Pthreads backend + + +Primary tested compiler are passing in release mode +with warnings as errors. They also are tested with a comprehensive set of +backend combinations (i.e. OpenMP, Pthreads, Serial, OpenMP+Serial, ...). +We are using the following set of flags: +* GCC: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wignored-qualifiers -Wempty-body + -Wclobbered -Wuninitialized + ```` +* Intel: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wuninitialized + ```` +* Clang: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wuninitialized + ```` + +* NVCC: + ```` + -Wall -Wshadow -pedantic + -Werror -Wsign-compare -Wtype-limits + -Wuninitialized + ```` + +Other compilers are tested occasionally, in particular when pushing from develop to +master branch. These are tested less rigorously without `-Werror` and only for a select set of backends. + +# Building and Installing Kokkos +Kokkos provide a CMake build system and a raw Makefile build system. +The CMake build system is strongly encouraged and will be the most rigorously supported in future releases. +Full details are given in the [build instructions](BUILD.md). Basic setups are shown here: + +## CMake + +The best way to install Kokkos is using the CMake build system. Assuming Kokkos lives in `$srcdir`: +```` +cmake $srcdir \ + -DCMAKE_CXX_COMPILER=$path_to_compiler \ + -DCMAKE_INSTALL_PREFIX=$path_to_install \ + -DKokkos_ENABLE_OPENMP=On \ + -DKokkos_ARCH_HSW=On \ + -DKokkos_ENABLE_HWLOC=On \ + -DKokkos_HWLOC_DIR=$path_to_hwloc +```` +then simply type `make install`. The Kokkos CMake package will then be installed in `$path_to_install` to be used by downstream packages. + +To validate the Kokkos build, configure with +```` + -DKokkos_ENABLE_TESTS=On +```` +and run `make test` after completing the build. + +For your CMake project using Kokkos, code such as the following: + +```` +find_package(Kokkos) +... +target_link_libraries(myTarget Kokkos::kokkos) +```` +should be added to your CMakeLists.txt. Your configure should additionally include +```` +-DKokkos_DIR=$path_to_install/cmake/lib/Kokkos +```` +or +```` +-DKokkos_ROOT=$path_to_install +```` +for the install location given above. + +## Spack +An alternative to manually building with the CMake is to use the Spack package manager. +To do so, download the `kokkos-spack` git repo and add to the package list: +```` +spack repo add $path-to-kokkos-spack +```` +A basic installation would be done as: +```` +spack install kokkos +```` +Spack allows options and and compilers to be tuned in the install command. +```` +spack install kokkos@3.0 %gcc@7.3.0 +openmp +```` +This example illustrates the three most common parameters to Spack: +* Variants: specified with, e.g. `+openmp`, this activates (or deactivates with, e.g. `~openmp`) certain options. +* Version: immediately following `kokkos` the `@version` can specify a particular Kokkos to build +* Compiler: a default compiler will be chosen if not specified, but an exact compiler version can be given with the `%`option. + +For a complete list of Kokkos options, run: +```` +spack info kokkos +```` +Spack currently installs packages to a location determined by a unique hash. This hash name is not really "human readable". +Generally, Spack usage should never really require you to reference the computer-generated unique install folder. +More details are given in the [build instructions](BUILD.md). If you must know, you can locate Spack Kokkos installations with: +```` +spack find -p kokkos ... +```` +where `...` is the unique spec identifying the particular Kokkos configuration and version. + + +## Raw Makefile +A bash script is provided to generate raw makefiles. +To install Kokkos as a library create a build directory and run the following +```` +$KOKKOS_PATH/generate_makefile.bash --prefix=$path_to_install +```` +Once the Makefile is generated, run: +```` +make kokkoslib +make install +```` +To additionally run the unit tests: +```` +make build-test +make test +```` +Run `generate_makefile.bash --help` for more detailed options such as +changing the device type for which to build. + +## Inline Builds vs. Installed Package +For individual projects, it may be preferable to build Kokkos inline rather than link to an installed package. +The main reason is that you may otherwise need many different +configurations of Kokkos installed depending on the required compile time +features an application needs. For example there is only one default +execution space, which means you need different installations to have OpenMP +or Pthreads as the default space. Also for the CUDA backend there are certain +choices, such as allowing relocatable device code, which must be made at +installation time. Building Kokkos inline uses largely the same process +as compiling an application against an installed Kokkos library. + +For CMake, this means copying over the Kokkos source code into your project and adding `add_subdirectory(kokkos)` to your CMakeLists.txt. + +For raw Makefiles, see the example benchmarks/bytes_and_flops/Makefile which can be used with an installed library and or an inline build. + +# Kokkos and CUDA UVM + +Kokkos does support UVM as a specific memory space called CudaUVMSpace. +Allocations made with that space are accessible from host and device. +You can tell Kokkos to use that as the default space for Cuda allocations. +In either case UVM comes with a number of restrictions: +* You can't access allocations on the host while a kernel is potentially +running. This will lead to segfaults. To avoid that you either need to +call Kokkos::Cuda::fence() (or just Kokkos::fence()), after kernels, or +you can set the environment variable CUDA_LAUNCH_BLOCKING=1. +* In multi socket multi GPU machines without NVLINK, UVM defaults +to using zero copy allocations for technical reasons related to using multiple +GPUs from the same process. If an executable doesn't do that (e.g. each +MPI rank of an application uses a single GPU [can be the same GPU for +multiple MPI ranks]) you can set CUDA_MANAGED_FORCE_DEVICE_ALLOC=1. +This will enforce proper UVM allocations, but can lead to errors if +more than a single GPU is used by a single process. + + +# Citing Kokkos + +If you publish work which mentions Kokkos, please cite the following paper: + +```` +@article{CarterEdwards20143202, + title = "Kokkos: Enabling manycore performance portability through polymorphic memory access patterns ", + journal = "Journal of Parallel and Distributed Computing ", + volume = "74", + number = "12", + pages = "3202 - 3216", + year = "2014", + note = "Domain-Specific Languages and High-Level Frameworks for High-Performance Computing ", + issn = "0743-7315", + doi = "https://doi.org/10.1016/j.jpdc.2014.07.003", + url = "http://www.sciencedirect.com/science/article/pii/S0743731514001257", + author = "H. Carter Edwards and Christian R. Trott and Daniel Sunderland" +} +```` + +##### [LICENSE](https://github.com/kokkos/kokkos/blob/master/LICENSE) + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) + +Under the terms of Contract DE-NA0003525 with NTESS, +the U.S. Government retains certain rights in this software. + diff --git a/lib/kokkos/algorithms/CMakeLists.txt b/lib/kokkos/algorithms/CMakeLists.txt index 507c9f2fdb..38747c152c 100644 --- a/lib/kokkos/algorithms/CMakeLists.txt +++ b/lib/kokkos/algorithms/CMakeLists.txt @@ -1,12 +1,12 @@ - - -TRIBITS_SUBPACKAGE(Algorithms) - -IF(KOKKOS_HAS_TRILINOS) - ADD_SUBDIRECTORY(src) -ENDIF() - -TRIBITS_ADD_TEST_DIRECTORIES(unit_tests) -#TRIBITS_ADD_TEST_DIRECTORIES(performance_tests) - -TRIBITS_SUBPACKAGE_POSTPROCESS() + + +KOKKOS_SUBPACKAGE(Algorithms) + +ADD_SUBDIRECTORY(src) + +KOKKOS_ADD_TEST_DIRECTORIES(unit_tests) + +KOKKOS_SUBPACKAGE_POSTPROCESS() + + + diff --git a/lib/kokkos/algorithms/src/CMakeLists.txt b/lib/kokkos/algorithms/src/CMakeLists.txt index dfbf3323c2..5afd319fcc 100644 --- a/lib/kokkos/algorithms/src/CMakeLists.txt +++ b/lib/kokkos/algorithms/src/CMakeLists.txt @@ -1,8 +1,9 @@ -TRIBITS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) +KOKKOS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) +#I have to leave these here for tribits +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) #----------------------------------------------------------------------------- @@ -12,10 +13,18 @@ LIST(APPEND HEADERS ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME}_config.h) #----------------------------------------------------------------------------- -TRIBITS_ADD_LIBRARY( - kokkosalgorithms - HEADERS ${HEADERS} - SOURCES ${SOURCES} - DEPLIBS - ) +# We have to pass the sources in here for Tribits +# These will get ignored for standalone CMake and a true interface library made +KOKKOS_ADD_INTERFACE_LIBRARY( + kokkosalgorithms + HEADERS ${HEADERS} + SOURCES ${SOURCES} +) +KOKKOS_LIB_INCLUDE_DIRECTORIES(kokkosalgorithms + ${KOKKOS_TOP_BUILD_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + + diff --git a/lib/kokkos/algorithms/src/Kokkos_Random.hpp b/lib/kokkos/algorithms/src/Kokkos_Random.hpp index da781de4fe..078db18edd 100644 --- a/lib/kokkos/algorithms/src/Kokkos_Random.hpp +++ b/lib/kokkos/algorithms/src/Kokkos_Random.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -59,6 +60,7 @@ namespace Kokkos { +// clang-format off /*Template functions to get equidistributed random numbers from a generator for a specific Scalar type template @@ -229,1019 +231,979 @@ namespace Kokkos { ViewType::value_type start, ViewType::value_type end); */ +// clang-format on - template - struct rand; - - - template - struct rand { - - KOKKOS_INLINE_FUNCTION - static short max(){return 127;} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen) - {return short((gen.rand()&0xff+256)%256);} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const char& range) - {return char(gen.rand(range));} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const char& start, const char& end) - {return char(gen.rand(start,end));} - - }; - - template - struct rand { - KOKKOS_INLINE_FUNCTION - static short max(){return 32767;} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen) - {return short((gen.rand()&0xffff+65536)%32768);} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const short& range) - {return short(gen.rand(range));} - KOKKOS_INLINE_FUNCTION - static short draw(Generator& gen, const short& start, const short& end) - {return short(gen.rand(start,end));} - - }; - - template - struct rand { - KOKKOS_INLINE_FUNCTION - static int max(){return Generator::MAX_RAND;} - KOKKOS_INLINE_FUNCTION - static int draw(Generator& gen) - {return gen.rand();} - KOKKOS_INLINE_FUNCTION - static int draw(Generator& gen, const int& range) - {return gen.rand(range);} - KOKKOS_INLINE_FUNCTION - static int draw(Generator& gen, const int& start, const int& end) - {return gen.rand(start,end);} +template +struct rand; - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static short max() { return 127; } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen) { + return short((gen.rand() & 0xff + 256) % 256); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const char& range) { + return char(gen.rand(range)); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const char& start, const char& end) { + return char(gen.rand(start, end)); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static unsigned int max () { - return Generator::MAX_URAND; - } - KOKKOS_INLINE_FUNCTION - static unsigned int draw (Generator& gen) { - return gen.urand (); - } - KOKKOS_INLINE_FUNCTION - static unsigned int draw(Generator& gen, const unsigned int& range) { - return gen.urand (range); - } - KOKKOS_INLINE_FUNCTION - static unsigned int - draw (Generator& gen, const unsigned int& start, const unsigned int& end) { - return gen.urand (start, end); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static short max() { return 32767; } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen) { + return short((gen.rand() & 0xffff + 65536) % 32768); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const short& range) { + return short(gen.rand(range)); + } + KOKKOS_INLINE_FUNCTION + static short draw(Generator& gen, const short& start, const short& end) { + return short(gen.rand(start, end)); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static long max () { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (Generator::MAX_RAND) : - static_cast (Generator::MAX_RAND64); - } - KOKKOS_INLINE_FUNCTION - static long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (gen.rand ()) : - static_cast (gen.rand64 ()); - } - KOKKOS_INLINE_FUNCTION - static long draw (Generator& gen, const long& range) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (gen.rand (static_cast (range))) : - static_cast (gen.rand64 (range)); - } - KOKKOS_INLINE_FUNCTION - static long draw (Generator& gen, const long& start, const long& end) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (long) == 4 ? - static_cast (gen.rand (static_cast (start), - static_cast (end))) : - static_cast (gen.rand64 (start, end)); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static int max() { return Generator::MAX_RAND; } + KOKKOS_INLINE_FUNCTION + static int draw(Generator& gen) { return gen.rand(); } + KOKKOS_INLINE_FUNCTION + static int draw(Generator& gen, const int& range) { return gen.rand(range); } + KOKKOS_INLINE_FUNCTION + static int draw(Generator& gen, const int& start, const int& end) { + return gen.rand(start, end); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static unsigned long max () { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (Generator::MAX_URAND) : - static_cast (Generator::MAX_URAND64); - } - KOKKOS_INLINE_FUNCTION - static unsigned long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (gen.urand ()) : - static_cast (gen.urand64 ()); - } - KOKKOS_INLINE_FUNCTION - static unsigned long draw(Generator& gen, const unsigned long& range) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (gen.urand (static_cast (range))) : - static_cast (gen.urand64 (range)); - } - KOKKOS_INLINE_FUNCTION - static unsigned long - draw (Generator& gen, const unsigned long& start, const unsigned long& end) { - // FIXME (mfh 26 Oct 2014) It would be better to select the - // return value at compile time, using something like enable_if. - return sizeof (unsigned long) == 4 ? - static_cast (gen.urand (static_cast (start), - static_cast (end))) : - static_cast (gen.urand64 (start, end)); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static unsigned int max() { return Generator::MAX_URAND; } + KOKKOS_INLINE_FUNCTION + static unsigned int draw(Generator& gen) { return gen.urand(); } + KOKKOS_INLINE_FUNCTION + static unsigned int draw(Generator& gen, const unsigned int& range) { + return gen.urand(range); + } + KOKKOS_INLINE_FUNCTION + static unsigned int draw(Generator& gen, const unsigned int& start, + const unsigned int& end) { + return gen.urand(start, end); + } +}; - // NOTE (mfh 26 oct 2014) This is a partial specialization for long - // long, a C99 / C++11 signed type which is guaranteed to be at - // least 64 bits. Do NOT write a partial specialization for - // int64_t!!! This is just a typedef! It could be either long or - // long long. We don't know which a priori, and I've seen both. - // The types long and long long are guaranteed to differ, so it's - // always safe to specialize for both. - template - struct rand { - KOKKOS_INLINE_FUNCTION - static long long max () { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return Generator::MAX_RAND64; - } - KOKKOS_INLINE_FUNCTION - static long long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.rand64 (); - } - KOKKOS_INLINE_FUNCTION - static long long draw (Generator& gen, const long long& range) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.rand64 (range); - } - KOKKOS_INLINE_FUNCTION - static long long draw (Generator& gen, const long long& start, const long long& end) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.rand64 (start, end); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static long max() { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 ? static_cast(Generator::MAX_RAND) + : static_cast(Generator::MAX_RAND64); + } + KOKKOS_INLINE_FUNCTION + static long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 ? static_cast(gen.rand()) + : static_cast(gen.rand64()); + } + KOKKOS_INLINE_FUNCTION + static long draw(Generator& gen, const long& range) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 + ? static_cast(gen.rand(static_cast(range))) + : static_cast(gen.rand64(range)); + } + KOKKOS_INLINE_FUNCTION + static long draw(Generator& gen, const long& start, const long& end) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(long) == 4 + ? static_cast( + gen.rand(static_cast(start), static_cast(end))) + : static_cast(gen.rand64(start, end)); + } +}; - // NOTE (mfh 26 oct 2014) This is a partial specialization for - // unsigned long long, a C99 / C++11 unsigned type which is - // guaranteed to be at least 64 bits. Do NOT write a partial - // specialization for uint64_t!!! This is just a typedef! It could - // be either unsigned long or unsigned long long. We don't know - // which a priori, and I've seen both. The types unsigned long and - // unsigned long long are guaranteed to differ, so it's always safe - // to specialize for both. - template - struct rand { - KOKKOS_INLINE_FUNCTION - static unsigned long long max () { - // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 bits. - return Generator::MAX_URAND64; - } - KOKKOS_INLINE_FUNCTION - static unsigned long long draw (Generator& gen) { - // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 bits. - return gen.urand64 (); - } - KOKKOS_INLINE_FUNCTION - static unsigned long long draw (Generator& gen, const unsigned long long& range) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.urand64 (range); - } - KOKKOS_INLINE_FUNCTION - static unsigned long long - draw (Generator& gen, const unsigned long long& start, const unsigned long long& end) { - // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. - return gen.urand64 (start, end); - } - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static unsigned long max() { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast(Generator::MAX_URAND) + : static_cast(Generator::MAX_URAND64); + } + KOKKOS_INLINE_FUNCTION + static unsigned long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast(gen.urand()) + : static_cast(gen.urand64()); + } + KOKKOS_INLINE_FUNCTION + static unsigned long draw(Generator& gen, const unsigned long& range) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast( + gen.urand(static_cast(range))) + : static_cast(gen.urand64(range)); + } + KOKKOS_INLINE_FUNCTION + static unsigned long draw(Generator& gen, const unsigned long& start, + const unsigned long& end) { + // FIXME (mfh 26 Oct 2014) It would be better to select the + // return value at compile time, using something like enable_if. + return sizeof(unsigned long) == 4 + ? static_cast( + gen.urand(static_cast(start), + static_cast(end))) + : static_cast(gen.urand64(start, end)); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static float max(){return 1.0f;} - KOKKOS_INLINE_FUNCTION - static float draw(Generator& gen) - {return gen.frand();} - KOKKOS_INLINE_FUNCTION - static float draw(Generator& gen, const float& range) - {return gen.frand(range);} - KOKKOS_INLINE_FUNCTION - static float draw(Generator& gen, const float& start, const float& end) - {return gen.frand(start,end);} +// NOTE (mfh 26 oct 2014) This is a partial specialization for long +// long, a C99 / C++11 signed type which is guaranteed to be at +// least 64 bits. Do NOT write a partial specialization for +// int64_t!!! This is just a typedef! It could be either long or +// long long. We don't know which a priori, and I've seen both. +// The types long and long long are guaranteed to differ, so it's +// always safe to specialize for both. +template +struct rand { + KOKKOS_INLINE_FUNCTION + static long long max() { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return Generator::MAX_RAND64; + } + KOKKOS_INLINE_FUNCTION + static long long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.rand64(); + } + KOKKOS_INLINE_FUNCTION + static long long draw(Generator& gen, const long long& range) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.rand64(range); + } + KOKKOS_INLINE_FUNCTION + static long long draw(Generator& gen, const long long& start, + const long long& end) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.rand64(start, end); + } +}; - }; +// NOTE (mfh 26 oct 2014) This is a partial specialization for +// unsigned long long, a C99 / C++11 unsigned type which is +// guaranteed to be at least 64 bits. Do NOT write a partial +// specialization for uint64_t!!! This is just a typedef! It could +// be either unsigned long or unsigned long long. We don't know +// which a priori, and I've seen both. The types unsigned long and +// unsigned long long are guaranteed to differ, so it's always safe +// to specialize for both. +template +struct rand { + KOKKOS_INLINE_FUNCTION + static unsigned long long max() { + // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 + // bits. + return Generator::MAX_URAND64; + } + KOKKOS_INLINE_FUNCTION + static unsigned long long draw(Generator& gen) { + // FIXME (mfh 26 Oct 2014) It's legal for unsigned long long to be > 64 + // bits. + return gen.urand64(); + } + KOKKOS_INLINE_FUNCTION + static unsigned long long draw(Generator& gen, + const unsigned long long& range) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.urand64(range); + } + KOKKOS_INLINE_FUNCTION + static unsigned long long draw(Generator& gen, + const unsigned long long& start, + const unsigned long long& end) { + // FIXME (mfh 26 Oct 2014) It's legal for long long to be > 64 bits. + return gen.urand64(start, end); + } +}; - template - struct rand { - KOKKOS_INLINE_FUNCTION - static double max(){return 1.0;} - KOKKOS_INLINE_FUNCTION - static double draw(Generator& gen) - {return gen.drand();} - KOKKOS_INLINE_FUNCTION - static double draw(Generator& gen, const double& range) - {return gen.drand(range);} - KOKKOS_INLINE_FUNCTION - static double draw(Generator& gen, const double& start, const double& end) - {return gen.drand(start,end);} +template +struct rand { + KOKKOS_INLINE_FUNCTION + static float max() { return 1.0f; } + KOKKOS_INLINE_FUNCTION + static float draw(Generator& gen) { return gen.frand(); } + KOKKOS_INLINE_FUNCTION + static float draw(Generator& gen, const float& range) { + return gen.frand(range); + } + KOKKOS_INLINE_FUNCTION + static float draw(Generator& gen, const float& start, const float& end) { + return gen.frand(start, end); + } +}; - }; +template +struct rand { + KOKKOS_INLINE_FUNCTION + static double max() { return 1.0; } + KOKKOS_INLINE_FUNCTION + static double draw(Generator& gen) { return gen.drand(); } + KOKKOS_INLINE_FUNCTION + static double draw(Generator& gen, const double& range) { + return gen.drand(range); + } + KOKKOS_INLINE_FUNCTION + static double draw(Generator& gen, const double& start, const double& end) { + return gen.drand(start, end); + } +}; - template - struct rand > { - KOKKOS_INLINE_FUNCTION - static Kokkos::complex max () { - return Kokkos::complex (1.0, 1.0); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen) { - const float re = gen.frand (); - const float im = gen.frand (); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& range) { - const float re = gen.frand (real (range)); - const float im = gen.frand (imag (range)); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& start, const Kokkos::complex& end) { - const float re = gen.frand (real (start), real (end)); - const float im = gen.frand (imag (start), imag (end)); - return Kokkos::complex (re, im); - } - }; +template +struct rand > { + KOKKOS_INLINE_FUNCTION + static Kokkos::complex max() { + return Kokkos::complex(1.0, 1.0); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen) { + const float re = gen.frand(); + const float im = gen.frand(); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& range) { + const float re = gen.frand(real(range)); + const float im = gen.frand(imag(range)); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& start, + const Kokkos::complex& end) { + const float re = gen.frand(real(start), real(end)); + const float im = gen.frand(imag(start), imag(end)); + return Kokkos::complex(re, im); + } +}; - template - struct rand > { - KOKKOS_INLINE_FUNCTION - static Kokkos::complex max () { - return Kokkos::complex (1.0, 1.0); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen) { - const double re = gen.drand (); - const double im = gen.drand (); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& range) { - const double re = gen.drand (real (range)); - const double im = gen.drand (imag (range)); - return Kokkos::complex (re, im); - } - KOKKOS_INLINE_FUNCTION - static Kokkos::complex draw (Generator& gen, const Kokkos::complex& start, const Kokkos::complex& end) { - const double re = gen.drand (real (start), real (end)); - const double im = gen.drand (imag (start), imag (end)); - return Kokkos::complex (re, im); - } - }; +template +struct rand > { + KOKKOS_INLINE_FUNCTION + static Kokkos::complex max() { + return Kokkos::complex(1.0, 1.0); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen) { + const double re = gen.drand(); + const double im = gen.drand(); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& range) { + const double re = gen.drand(real(range)); + const double im = gen.drand(imag(range)); + return Kokkos::complex(re, im); + } + KOKKOS_INLINE_FUNCTION + static Kokkos::complex draw(Generator& gen, + const Kokkos::complex& start, + const Kokkos::complex& end) { + const double re = gen.drand(real(start), real(end)); + const double im = gen.drand(imag(start), imag(end)); + return Kokkos::complex(re, im); + } +}; - template - class Random_XorShift64_Pool; +template +class Random_XorShift64_Pool; - template - class Random_XorShift64 { - private: - uint64_t state_; - const int state_idx_; - friend class Random_XorShift64_Pool; - public: +template +class Random_XorShift64 { + private: + uint64_t state_; + const int state_idx_; + friend class Random_XorShift64_Pool; - typedef DeviceType device_type; + public: + typedef DeviceType device_type; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffff/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffLL/2-1)}; + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffff / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffLL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - Random_XorShift64 (uint64_t state, int state_idx = 0) - : state_(state==0?uint64_t(1318319):state),state_idx_(state_idx){} + KOKKOS_INLINE_FUNCTION + Random_XorShift64(uint64_t state, int state_idx = 0) + : state_(state == 0 ? uint64_t(1318319) : state), state_idx_(state_idx) {} - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - state_ ^= state_ >> 12; - state_ ^= state_ << 25; - state_ ^= state_ >> 27; - - uint64_t tmp = state_ * 2685821657736338717ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + state_ ^= state_ >> 12; + state_ ^= state_ << 25; + state_ ^= state_ >> 27; + + uint64_t tmp = state_ * 2685821657736338717ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - state_ ^= state_ >> 12; - state_ ^= state_ << 25; - state_ ^= state_ >> 27; - return (state_ * 2685821657736338717ULL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + state_ ^= state_ >> 12; + state_ ^= state_ << 25; + state_ ^= state_ >> 27; + return (state_ * 2685821657736338717ULL) - 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - tmp = urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) tmp = urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - tmp = urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) tmp = urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - tmp = rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) tmp = rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - tmp = rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) tmp = rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return drand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return drand(end - start) + start; + } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; - }; +template +class Random_XorShift64_Pool { + private: + typedef View lock_type; + typedef View state_data_type; + lock_type locks_; + state_data_type state_; + int num_states_; - template - class Random_XorShift64_Pool { - private: - typedef View lock_type; - typedef View state_data_type; - lock_type locks_; - state_data_type state_; - int num_states_; - - public: - typedef Random_XorShift64 generator_type; - typedef DeviceType device_type; + public: + typedef Random_XorShift64 generator_type; + typedef DeviceType device_type; - KOKKOS_INLINE_FUNCTION - Random_XorShift64_Pool() { - num_states_ = 0; - } - Random_XorShift64_Pool(uint64_t seed) { - num_states_ = 0; + KOKKOS_INLINE_FUNCTION + Random_XorShift64_Pool() { num_states_ = 0; } + Random_XorShift64_Pool(uint64_t seed) { + num_states_ = 0; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - init(seed,DeviceType::max_hardware_threads()); + init(seed, DeviceType::max_hardware_threads()); #else - init(seed,DeviceType::impl_max_hardware_threads()); + init(seed, DeviceType::impl_max_hardware_threads()); #endif - } + } - KOKKOS_INLINE_FUNCTION - Random_XorShift64_Pool(const Random_XorShift64_Pool& src): - locks_(src.locks_), - state_(src.state_), - num_states_(src.num_states_) - {} + KOKKOS_INLINE_FUNCTION + Random_XorShift64_Pool(const Random_XorShift64_Pool& src) + : locks_(src.locks_), state_(src.state_), num_states_(src.num_states_) {} - KOKKOS_INLINE_FUNCTION - Random_XorShift64_Pool operator = (const Random_XorShift64_Pool& src) { - locks_ = src.locks_; - state_ = src.state_; - num_states_ = src.num_states_; - return *this; - } + KOKKOS_INLINE_FUNCTION + Random_XorShift64_Pool operator=(const Random_XorShift64_Pool& src) { + locks_ = src.locks_; + state_ = src.state_; + num_states_ = src.num_states_; + return *this; + } - void init(uint64_t seed, int num_states) { - if(seed==0) - seed = uint64_t(1318319); - - num_states_ = num_states; - - locks_ = lock_type("Kokkos::Random_XorShift64::locks",num_states_); - state_ = state_data_type("Kokkos::Random_XorShift64::state",num_states_); - - typename state_data_type::HostMirror h_state = create_mirror_view(state_); - typename lock_type::HostMirror h_lock = create_mirror_view(locks_); - - // Execute on the HostMirror's default execution space. - Random_XorShift64 gen(seed,0); - for(int i = 0; i < 17; i++) - gen.rand(); - for(int i = 0; i < num_states_; i++) { - int n1 = gen.rand(); - int n2 = gen.rand(); - int n3 = gen.rand(); - int n4 = gen.rand(); - h_state(i) = (((static_cast(n1)) & 0xffff)<<00) | - (((static_cast(n2)) & 0xffff)<<16) | - (((static_cast(n3)) & 0xffff)<<32) | - (((static_cast(n4)) & 0xffff)<<48); - h_lock(i) = 0; - } - deep_copy(state_,h_state); - deep_copy(locks_,h_lock); - } + void init(uint64_t seed, int num_states) { + if (seed == 0) seed = uint64_t(1318319); + + num_states_ = num_states; + + locks_ = lock_type("Kokkos::Random_XorShift64::locks", num_states_); + state_ = state_data_type("Kokkos::Random_XorShift64::state", num_states_); + + typename state_data_type::HostMirror h_state = create_mirror_view(state_); + typename lock_type::HostMirror h_lock = create_mirror_view(locks_); + + // Execute on the HostMirror's default execution space. + Random_XorShift64 + gen(seed, 0); + for (int i = 0; i < 17; i++) gen.rand(); + for (int i = 0; i < num_states_; i++) { + int n1 = gen.rand(); + int n2 = gen.rand(); + int n3 = gen.rand(); + int n4 = gen.rand(); + h_state(i) = (((static_cast(n1)) & 0xffff) << 00) | + (((static_cast(n2)) & 0xffff) << 16) | + (((static_cast(n3)) & 0xffff) << 32) | + (((static_cast(n4)) & 0xffff) << 48); + h_lock(i) = 0; + } + deep_copy(state_, h_state); + deep_copy(locks_, h_lock); + } - KOKKOS_INLINE_FUNCTION - Random_XorShift64 get_state() const { + KOKKOS_INLINE_FUNCTION + Random_XorShift64 get_state() const { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - const int i = DeviceType::hardware_thread_id();; + const int i = DeviceType::hardware_thread_id(); + ; #else - const int i = DeviceType::impl_hardware_thread_id();; + const int i = DeviceType::impl_hardware_thread_id(); + ; #endif - return Random_XorShift64(state_(i),i); - } - - // NOTE: state_idx MUST be unique and less than num_states - KOKKOS_INLINE_FUNCTION - Random_XorShift64 get_state(const int state_idx) const { - return Random_XorShift64(state_(state_idx),state_idx); - } - - KOKKOS_INLINE_FUNCTION - void free_state(const Random_XorShift64& state) const { - state_(state.state_idx_) = state.state_; - } - }; + return Random_XorShift64(state_(i), i); + } + // NOTE: state_idx MUST be unique and less than num_states + KOKKOS_INLINE_FUNCTION + Random_XorShift64 get_state(const int state_idx) const { + return Random_XorShift64(state_(state_idx), state_idx); + } - template - class Random_XorShift1024_Pool; + KOKKOS_INLINE_FUNCTION + void free_state(const Random_XorShift64& state) const { + state_(state.state_idx_) = state.state_; + } +}; - template - class Random_XorShift1024 { - private: - int p_; - const int state_idx_; - uint64_t state_[16]; - friend class Random_XorShift1024_Pool; - public: +template +class Random_XorShift1024_Pool; - typedef Random_XorShift1024_Pool pool_type; - typedef DeviceType device_type; +template +class Random_XorShift1024 { + private: + int p_; + const int state_idx_; + uint64_t state_[16]; + friend class Random_XorShift1024_Pool; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffffU/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffULL/2-1)}; + public: + typedef Random_XorShift1024_Pool pool_type; + typedef DeviceType device_type; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 (const typename pool_type::state_data_type& state, int p, int state_idx = 0): - p_(p),state_idx_(state_idx){ - for(int i=0 ; i<16; i++) - state_[i] = state(state_idx,i); - } + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffffU / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffULL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - uint64_t state_0 = state_[ p_ ]; - uint64_t state_1 = state_[ p_ = ( p_ + 1 ) & 15 ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - uint64_t tmp = ( state_[ p_ ] = state_0 ^ state_1 ) * 1181783497276652981ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024(const typename pool_type::state_data_type& state, int p, + int state_idx = 0) + : p_(p), state_idx_(state_idx) { + for (int i = 0; i < 16; i++) state_[i] = state(state_idx, i); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - uint64_t state_0 = state_[ p_ ]; - uint64_t state_1 = state_[ p_ = ( p_ + 1 ) & 15 ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - return (( state_[ p_ ] = state_0 ^ state_1 ) * 1181783497276652981LL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + uint64_t state_0 = state_[p_]; + uint64_t state_1 = state_[p_ = (p_ + 1) & 15]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + uint64_t tmp = (state_[p_] = state_0 ^ state_1) * 1181783497276652981ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - tmp = urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + uint64_t state_0 = state_[p_]; + uint64_t state_1 = state_[p_ = (p_ + 1) & 15]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + return ((state_[p_] = state_0 ^ state_1) * 1181783497276652981LL) - 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) tmp = urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - tmp = urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) tmp = urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - tmp = rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) tmp = rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - tmp = rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) tmp = rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } - }; + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; - template - class Random_XorShift1024_Pool { - private: - typedef View int_view_type; - typedef View state_data_type; +template +class Random_XorShift1024_Pool { + private: + typedef View int_view_type; + typedef View state_data_type; - int_view_type locks_; - state_data_type state_; - int_view_type p_; - int num_states_; - friend class Random_XorShift1024; + int_view_type locks_; + state_data_type state_; + int_view_type p_; + int num_states_; + friend class Random_XorShift1024; - public: - typedef Random_XorShift1024 generator_type; + public: + typedef Random_XorShift1024 generator_type; - typedef DeviceType device_type; + typedef DeviceType device_type; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024_Pool() { - num_states_ = 0; - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024_Pool() { num_states_ = 0; } - inline - Random_XorShift1024_Pool(uint64_t seed){ - num_states_ = 0; + inline Random_XorShift1024_Pool(uint64_t seed) { + num_states_ = 0; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - init(seed,DeviceType::max_hardware_threads()); + init(seed, DeviceType::max_hardware_threads()); #else - init(seed,DeviceType::impl_max_hardware_threads()); + init(seed, DeviceType::impl_max_hardware_threads()); #endif - } + } - KOKKOS_INLINE_FUNCTION - Random_XorShift1024_Pool(const Random_XorShift1024_Pool& src): - locks_(src.locks_), - state_(src.state_), - p_(src.p_), - num_states_(src.num_states_) - {} + KOKKOS_INLINE_FUNCTION + Random_XorShift1024_Pool(const Random_XorShift1024_Pool& src) + : locks_(src.locks_), + state_(src.state_), + p_(src.p_), + num_states_(src.num_states_) {} - KOKKOS_INLINE_FUNCTION - Random_XorShift1024_Pool operator = (const Random_XorShift1024_Pool& src) { - locks_ = src.locks_; - state_ = src.state_; - p_ = src.p_; - num_states_ = src.num_states_; - return *this; - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024_Pool operator=(const Random_XorShift1024_Pool& src) { + locks_ = src.locks_; + state_ = src.state_; + p_ = src.p_; + num_states_ = src.num_states_; + return *this; + } - inline - void init(uint64_t seed, int num_states) { - if(seed==0) - seed = uint64_t(1318319); - num_states_ = num_states; - locks_ = int_view_type("Kokkos::Random_XorShift1024::locks",num_states_); - state_ = state_data_type("Kokkos::Random_XorShift1024::state",num_states_); - p_ = int_view_type("Kokkos::Random_XorShift1024::p",num_states_); - - typename state_data_type::HostMirror h_state = create_mirror_view(state_); - typename int_view_type::HostMirror h_lock = create_mirror_view(locks_); - typename int_view_type::HostMirror h_p = create_mirror_view(p_); - - // Execute on the HostMirror's default execution space. - Random_XorShift64 gen(seed,0); - for(int i = 0; i < 17; i++) - gen.rand(); - for(int i = 0; i < num_states_; i++) { - for(int j = 0; j < 16 ; j++) { - int n1 = gen.rand(); - int n2 = gen.rand(); - int n3 = gen.rand(); - int n4 = gen.rand(); - h_state(i,j) = (((static_cast(n1)) & 0xffff)<<00) | - (((static_cast(n2)) & 0xffff)<<16) | - (((static_cast(n3)) & 0xffff)<<32) | - (((static_cast(n4)) & 0xffff)<<48); - } - h_p(i) = 0; - h_lock(i) = 0; + inline void init(uint64_t seed, int num_states) { + if (seed == 0) seed = uint64_t(1318319); + num_states_ = num_states; + locks_ = int_view_type("Kokkos::Random_XorShift1024::locks", num_states_); + state_ = state_data_type("Kokkos::Random_XorShift1024::state", num_states_); + p_ = int_view_type("Kokkos::Random_XorShift1024::p", num_states_); + + typename state_data_type::HostMirror h_state = create_mirror_view(state_); + typename int_view_type::HostMirror h_lock = create_mirror_view(locks_); + typename int_view_type::HostMirror h_p = create_mirror_view(p_); + + // Execute on the HostMirror's default execution space. + Random_XorShift64 + gen(seed, 0); + for (int i = 0; i < 17; i++) gen.rand(); + for (int i = 0; i < num_states_; i++) { + for (int j = 0; j < 16; j++) { + int n1 = gen.rand(); + int n2 = gen.rand(); + int n3 = gen.rand(); + int n4 = gen.rand(); + h_state(i, j) = (((static_cast(n1)) & 0xffff) << 00) | + (((static_cast(n2)) & 0xffff) << 16) | + (((static_cast(n3)) & 0xffff) << 32) | + (((static_cast(n4)) & 0xffff) << 48); } - deep_copy(state_,h_state); - deep_copy(locks_,h_lock); + h_p(i) = 0; + h_lock(i) = 0; } + deep_copy(state_, h_state); + deep_copy(locks_, h_lock); + } - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 get_state() const { + KOKKOS_INLINE_FUNCTION + Random_XorShift1024 get_state() const { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - const int i = DeviceType::hardware_thread_id(); + const int i = DeviceType::hardware_thread_id(); #else - const int i = DeviceType::impl_hardware_thread_id(); + const int i = DeviceType::impl_hardware_thread_id(); #endif - return Random_XorShift1024(state_,p_(i),i); - }; + return Random_XorShift1024(state_, p_(i), i); + }; - // NOTE: state_idx MUST be unique and less than num_states - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 get_state(const int state_idx) const { - return Random_XorShift1024(state_,p_(state_idx),state_idx); - } + // NOTE: state_idx MUST be unique and less than num_states + KOKKOS_INLINE_FUNCTION + Random_XorShift1024 get_state(const int state_idx) const { + return Random_XorShift1024(state_, p_(state_idx), state_idx); + } - KOKKOS_INLINE_FUNCTION - void free_state(const Random_XorShift1024& state) const { - for(int i = 0; i<16; i++) - state_(state.state_idx_,i) = state.state_[i]; - p_(state.state_idx_) = state.p_; - } - }; + KOKKOS_INLINE_FUNCTION + void free_state(const Random_XorShift1024& state) const { + for (int i = 0; i < 16; i++) state_(state.state_idx_, i) = state.state_[i]; + p_(state.state_idx_) = state.p_; + } +}; #if defined(KOKKOS_ENABLE_CUDA) && defined(__CUDACC__) - template<> - class Random_XorShift1024 { - private: - int p_; - const int state_idx_; - uint64_t* state_; - const int stride_; - friend class Random_XorShift1024_Pool; - public: +template <> +class Random_XorShift1024 { + private: + int p_; + const int state_idx_; + uint64_t* state_; + const int stride_; + friend class Random_XorShift1024_Pool; - typedef Kokkos::Cuda device_type; - typedef Random_XorShift1024_Pool pool_type; + public: + typedef Kokkos::Cuda device_type; + typedef Random_XorShift1024_Pool pool_type; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffffU/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffULL/2-1)}; + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffffU / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffULL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 (const typename pool_type::state_data_type& state, int p, int state_idx = 0): - p_(p),state_idx_(state_idx),state_(&state(state_idx,0)),stride_(state.stride_1()){ - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024(const typename pool_type::state_data_type& state, int p, + int state_idx = 0) + : p_(p), + state_idx_(state_idx), + state_(&state(state_idx, 0)), + stride_(state.stride_1()) {} - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - uint64_t tmp = ( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + uint64_t tmp = + (state_[p_ * stride_] = state_0 ^ state_1) * 1181783497276652981ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - return (( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981LL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + return ((state_[p_ * stride_] = state_0 ^ state_1) * + 1181783497276652981LL) - + 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return frand(end - start) + start; + } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } - }; + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; -template<> -inline -Random_XorShift64_Pool::Random_XorShift64_Pool(uint64_t seed) { +template <> +inline Random_XorShift64_Pool::Random_XorShift64_Pool( + uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift64 Random_XorShift64_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift64 +Random_XorShift64_Pool::get_state() const { #ifdef __CUDA_ARCH__ - const int i_offset = (threadIdx.x*blockDim.y + threadIdx.y)*blockDim.z+threadIdx.z; - int i = (((blockIdx.x*gridDim.y+blockIdx.y)*gridDim.z + blockIdx.z) * - blockDim.x*blockDim.y*blockDim.z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim.x*blockDim.y*blockDim.z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx.x * blockDim.y + threadIdx.y) * blockDim.z + threadIdx.z; + int i = (((blockIdx.x * gridDim.y + blockIdx.y) * gridDim.z + blockIdx.z) * + blockDim.x * blockDim.y * blockDim.z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim.x * blockDim.y * blockDim.z; + if (i >= num_states_) { + i = i_offset; + } } - return Random_XorShift64(state_(i),i); + return Random_XorShift64(state_(i), i); #else - return Random_XorShift64(state_(0),0); + return Random_XorShift64(state_(0), 0); #endif } -template<> -KOKKOS_INLINE_FUNCTION -void Random_XorShift64_Pool::free_state(const Random_XorShift64 &state) const { +template <> +KOKKOS_INLINE_FUNCTION void Random_XorShift64_Pool::free_state( + const Random_XorShift64& state) const { state_(state.state_idx_) = state.state_; #ifdef __CUDA_ARCH__ locks_(state.state_idx_) = 0; @@ -1249,24 +1211,28 @@ void Random_XorShift64_Pool::free_state(const Random_XorShift64 -inline -Random_XorShift1024_Pool::Random_XorShift1024_Pool(uint64_t seed) { +template <> +inline Random_XorShift1024_Pool::Random_XorShift1024_Pool( + uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift1024 Random_XorShift1024_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift1024 +Random_XorShift1024_Pool::get_state() const { #ifdef __CUDA_ARCH__ - const int i_offset = (threadIdx.x*blockDim.y + threadIdx.y)*blockDim.z+threadIdx.z; - int i = (((blockIdx.x*gridDim.y+blockIdx.y)*gridDim.z + blockIdx.z) * - blockDim.x*blockDim.y*blockDim.z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim.x*blockDim.y*blockDim.z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx.x * blockDim.y + threadIdx.y) * blockDim.z + threadIdx.z; + int i = (((blockIdx.x * gridDim.y + blockIdx.y) * gridDim.z + blockIdx.z) * + blockDim.x * blockDim.y * blockDim.z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim.x * blockDim.y * blockDim.z; + if (i >= num_states_) { + i = i_offset; + } } return Random_XorShift1024(state_, p_(i), i); @@ -1275,210 +1241,205 @@ Random_XorShift1024 Random_XorShift1024_Pool::get_st #endif } -template<> -KOKKOS_INLINE_FUNCTION -void Random_XorShift1024_Pool::free_state(const Random_XorShift1024 &state) const { - for(int i=0; i<16; i++) - state_(state.state_idx_,i) = state.state_[i]; +template <> +KOKKOS_INLINE_FUNCTION void Random_XorShift1024_Pool::free_state( + const Random_XorShift1024& state) const { + for (int i = 0; i < 16; i++) state_(state.state_idx_, i) = state.state_[i]; #ifdef __CUDA_ARCH__ locks_(state.state_idx_) = 0; return; #endif } - #endif -#if defined(KOKKOS_ENABLE_ROCM) +#if defined(KOKKOS_ENABLE_ROCM) - template<> - class Random_XorShift1024 { - private: - int p_; - const int state_idx_; - uint64_t* state_; - const int stride_; - friend class Random_XorShift1024_Pool; - public: +template <> +class Random_XorShift1024 { + private: + int p_; + const int state_idx_; + uint64_t* state_; + const int stride_; + friend class Random_XorShift1024_Pool; - typedef Kokkos::Experimental::ROCm device_type; - typedef Random_XorShift1024_Pool pool_type; + public: + typedef Kokkos::Experimental::ROCm device_type; + typedef Random_XorShift1024_Pool pool_type; - enum {MAX_URAND = 0xffffffffU}; - enum {MAX_URAND64 = 0xffffffffffffffffULL-1}; - enum {MAX_RAND = static_cast(0xffffffffU/2)}; - enum {MAX_RAND64 = static_cast(0xffffffffffffffffULL/2-1)}; + enum { MAX_URAND = 0xffffffffU }; + enum { MAX_URAND64 = 0xffffffffffffffffULL - 1 }; + enum { MAX_RAND = static_cast(0xffffffffU / 2) }; + enum { MAX_RAND64 = static_cast(0xffffffffffffffffULL / 2 - 1) }; - KOKKOS_INLINE_FUNCTION - Random_XorShift1024 (const typename pool_type::state_data_type& state, int p, int state_idx = 0): - p_(p),state_idx_(state_idx),state_(&state(state_idx,0)),stride_(state.stride_1()){ - } + KOKKOS_INLINE_FUNCTION + Random_XorShift1024(const typename pool_type::state_data_type& state, int p, + int state_idx = 0) + : p_(p), + state_idx_(state_idx), + state_(&state(state_idx, 0)), + stride_(state.stride_1()) {} - KOKKOS_INLINE_FUNCTION - uint32_t urand() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - uint64_t tmp = ( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981ULL; - tmp = tmp>>16; - return static_cast(tmp&MAX_URAND); - } + KOKKOS_INLINE_FUNCTION + uint32_t urand() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + uint64_t tmp = + (state_[p_ * stride_] = state_0 ^ state_1) * 1181783497276652981ULL; + tmp = tmp >> 16; + return static_cast(tmp & MAX_URAND); + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64() { - uint64_t state_0 = state_[ p_ * stride_ ]; - uint64_t state_1 = state_[ (p_ = ( p_ + 1 ) & 15) * stride_ ]; - state_1 ^= state_1 << 31; - state_1 ^= state_1 >> 11; - state_0 ^= state_0 >> 30; - return (( state_[ p_ * stride_ ] = state_0 ^ state_1 ) * 1181783497276652981LL) - 1; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64() { + uint64_t state_0 = state_[p_ * stride_]; + uint64_t state_1 = state_[(p_ = (p_ + 1) & 15) * stride_]; + state_1 ^= state_1 << 31; + state_1 ^= state_1 >> 11; + state_0 ^= state_0 >> 30; + return ((state_[p_ * stride_] = state_0 ^ state_1) * + 1181783497276652981LL) - + 1; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& range) { - const uint32_t max_val = (MAX_URAND/range)*range; - uint32_t tmp = urand(); - while(tmp>=max_val) - urand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& range) { + const uint32_t max_val = (MAX_URAND / range) * range; + uint32_t tmp = urand(); + while (tmp >= max_val) urand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint32_t urand(const uint32_t& start, const uint32_t& end ) { - return urand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint32_t urand(const uint32_t& start, const uint32_t& end) { + return urand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& range) { - const uint64_t max_val = (MAX_URAND64/range)*range; - uint64_t tmp = urand64(); - while(tmp>=max_val) - urand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& range) { + const uint64_t max_val = (MAX_URAND64 / range) * range; + uint64_t tmp = urand64(); + while (tmp >= max_val) urand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - uint64_t urand64(const uint64_t& start, const uint64_t& end ) { - return urand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + uint64_t urand64(const uint64_t& start, const uint64_t& end) { + return urand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int rand() { - return static_cast(urand()/2); - } + KOKKOS_INLINE_FUNCTION + int rand() { return static_cast(urand() / 2); } - KOKKOS_INLINE_FUNCTION - int rand(const int& range) { - const int max_val = (MAX_RAND/range)*range; - int tmp = rand(); - while(tmp>=max_val) - rand(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& range) { + const int max_val = (MAX_RAND / range) * range; + int tmp = rand(); + while (tmp >= max_val) rand(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int rand(const int& start, const int& end ) { - return rand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int rand(const int& start, const int& end) { + return rand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64() { - return static_cast(urand64()/2); - } + KOKKOS_INLINE_FUNCTION + int64_t rand64() { return static_cast(urand64() / 2); } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& range) { - const int64_t max_val = (MAX_RAND64/range)*range; - int64_t tmp = rand64(); - while(tmp>=max_val) - rand64(); - return tmp%range; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& range) { + const int64_t max_val = (MAX_RAND64 / range) * range; + int64_t tmp = rand64(); + while (tmp >= max_val) rand64(); + return tmp % range; + } - KOKKOS_INLINE_FUNCTION - int64_t rand64(const int64_t& start, const int64_t& end ) { - return rand64(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + int64_t rand64(const int64_t& start, const int64_t& end) { + return rand64(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - float frand() { - return 1.0f * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand() { return 1.0f * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - float frand(const float& start, const float& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + float frand(const float& start, const float& end) { + return frand(end - start) + start; + } - KOKKOS_INLINE_FUNCTION - double drand() { - return 1.0 * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand() { return 1.0 * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& range) { - return range * urand64()/MAX_URAND64; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& range) { return range * urand64() / MAX_URAND64; } - KOKKOS_INLINE_FUNCTION - double drand(const double& start, const double& end ) { - return frand(end-start)+start; - } + KOKKOS_INLINE_FUNCTION + double drand(const double& start, const double& end) { + return frand(end - start) + start; + } - //Marsaglia polar method for drawing a standard normal distributed random number - KOKKOS_INLINE_FUNCTION - double normal() { - double S = 2.0; - double U; - while(S>=1.0) { - U = 2.0*drand() - 1.0; - const double V = 2.0*drand() - 1.0; - S = U*U+V*V; - } - return U*std::sqrt(-2.0*log(S)/S); - } + // Marsaglia polar method for drawing a standard normal distributed random + // number + KOKKOS_INLINE_FUNCTION + double normal() { + double S = 2.0; + double U; + while (S >= 1.0) { + U = 2.0 * drand() - 1.0; + const double V = 2.0 * drand() - 1.0; + S = U * U + V * V; + } + return U * std::sqrt(-2.0 * log(S) / S); + } - KOKKOS_INLINE_FUNCTION - double normal(const double& mean, const double& std_dev=1.0) { - return mean + normal()*std_dev; - } - }; + KOKKOS_INLINE_FUNCTION + double normal(const double& mean, const double& std_dev = 1.0) { + return mean + normal() * std_dev; + } +}; -template<> -inline -Random_XorShift64_Pool::Random_XorShift64_Pool(uint64_t seed) { +template <> +inline Random_XorShift64_Pool< + Kokkos::Experimental::ROCm>::Random_XorShift64_Pool(uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift64 Random_XorShift64_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift64 +Random_XorShift64_Pool::get_state() const { #ifdef __HCC_ACCELERATOR__ - const int i_offset = (threadIdx_x*blockDim_y + threadIdx_y)*blockDim_z+threadIdx_z; - int i = (((blockIdx_x*gridDim_y+blockIdx_y)*gridDim_z + blockIdx_z) * - blockDim_x*blockDim_y*blockDim_z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim_x*blockDim_y*blockDim_z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx_x * blockDim_y + threadIdx_y) * blockDim_z + threadIdx_z; + int i = (((blockIdx_x * gridDim_y + blockIdx_y) * gridDim_z + blockIdx_z) * + blockDim_x * blockDim_y * blockDim_z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim_x * blockDim_y * blockDim_z; + if (i >= num_states_) { + i = i_offset; + } } - return Random_XorShift64(state_(i),i); + return Random_XorShift64(state_(i), i); #else - return Random_XorShift64(state_(0),0); + return Random_XorShift64(state_(0), 0); #endif } -template<> -KOKKOS_INLINE_FUNCTION -void Random_XorShift64_Pool::free_state(const Random_XorShift64 &state) const { +template <> +KOKKOS_INLINE_FUNCTION void +Random_XorShift64_Pool::free_state( + const Random_XorShift64& state) const { #ifdef __HCC_ACCELERATOR__ state_(state.state_idx_) = state.state_; locks_(state.state_idx_) = 0; @@ -1486,24 +1447,28 @@ void Random_XorShift64_Pool::free_state(const Random #endif } - -template<> -inline -Random_XorShift1024_Pool::Random_XorShift1024_Pool(uint64_t seed) { +template <> +inline Random_XorShift1024_Pool< + Kokkos::Experimental::ROCm>::Random_XorShift1024_Pool(uint64_t seed) { num_states_ = 0; - init(seed,4*32768); + init(seed, 4 * 32768); } -template<> -KOKKOS_INLINE_FUNCTION -Random_XorShift1024 Random_XorShift1024_Pool::get_state() const { +template <> +KOKKOS_INLINE_FUNCTION Random_XorShift1024 +Random_XorShift1024_Pool::get_state() const { #ifdef __HCC_ACCELERATOR__ - const int i_offset = (threadIdx_x*blockDim_y + threadIdx_y)*blockDim_z+threadIdx_z; - int i = (((blockIdx_x*gridDim_y+blockIdx_y)*gridDim_z + blockIdx_z) * - blockDim_x*blockDim_y*blockDim_z + i_offset)%num_states_; - while(Kokkos::atomic_compare_exchange(&locks_(i),0,1)) { - i+=blockDim_x*blockDim_y*blockDim_z; - if(i>=num_states_) {i = i_offset;} + const int i_offset = + (threadIdx_x * blockDim_y + threadIdx_y) * blockDim_z + threadIdx_z; + int i = (((blockIdx_x * gridDim_y + blockIdx_y) * gridDim_z + blockIdx_z) * + blockDim_x * blockDim_y * blockDim_z + + i_offset) % + num_states_; + while (Kokkos::atomic_compare_exchange(&locks_(i), 0, 1)) { + i += blockDim_x * blockDim_y * blockDim_z; + if (i >= num_states_) { + i = i_offset; + } } return Random_XorShift1024(state_, p_(i), i); @@ -1512,515 +1477,589 @@ Random_XorShift1024 Random_XorShift1024_Pool -KOKKOS_INLINE_FUNCTION -void Random_XorShift1024_Pool::free_state(const Random_XorShift1024 &state) const { +template <> +KOKKOS_INLINE_FUNCTION void +Random_XorShift1024_Pool::free_state( + const Random_XorShift1024& state) const { #ifdef __HCC_ACCELERATOR__ - for(int i=0; i<16; i++) - state_(state.state_idx_,i) = state.state_[i]; + for (int i = 0; i < 16; i++) state_(state.state_idx_, i) = state.state_[i]; locks_(state.state_idx_) = 0; return; #endif } - #endif - namespace Impl { -template +template struct fill_random_functor_range; -template +template struct fill_random_functor_begin_end; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (const IndexType& i) const { + void operator()(const IndexType& i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) - a(idx) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) + a(idx) = Rand::draw(gen, range); } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - a(idx,k) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + a(idx, k) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; - -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - a(idx,k,l) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + a(idx, k, l) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - a(idx,k,l,m) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + a(idx, k, l, m) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - a(idx,k,l,m,n) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + a(idx, k, l, m, n) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - a(idx,k,l,m,n,o) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + a(idx, k, l, m, n, o) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - a(idx,k,l,m,n,o,p) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + a(idx, k, l, m, n, o, p) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_range{ +template +struct fill_random_functor_range { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; typename ViewType::const_value_type range; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_range(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type range_): - a(a_),rand_pool(rand_pool_),range(range_) {} + typename ViewType::const_value_type range_) + : a(a_), rand_pool(rand_pool_), range(range_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - for(IndexType q=0;q(a.extent(7));q++) - a(idx,k,l,m,n,o,p,q) = Rand::draw(gen,range); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + for (IndexType q = 0; + q < static_cast(a.extent(7)); q++) + a(idx, k, l, m, n, o, p, q) = Rand::draw(gen, range); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) - a(idx) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) + a(idx) = Rand::draw(gen, begin, end); } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - a(idx,k) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + a(idx, k) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; - -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - a(idx,k,l) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + a(idx, k, l) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - a(idx,k,l,m) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + a(idx, k, l, m) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))){ - for(IndexType l=0;l(a.extent(1));l++) - for(IndexType m=0;m(a.extent(2));m++) - for(IndexType n=0;n(a.extent(3));n++) - for(IndexType o=0;o(a.extent(4));o++) - a(idx,l,m,n,o) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType l = 0; l < static_cast(a.extent(1)); l++) + for (IndexType m = 0; m < static_cast(a.extent(2)); m++) + for (IndexType n = 0; n < static_cast(a.extent(3)); n++) + for (IndexType o = 0; o < static_cast(a.extent(4)); + o++) + a(idx, l, m, n, o) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - a(idx,k,l,m,n,o) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + a(idx, k, l, m, n, o) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; - -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - a(idx,k,l,m,n,o,p) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + a(idx, k, l, m, n, o, p) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -template -struct fill_random_functor_begin_end{ +template +struct fill_random_functor_begin_end { typedef typename ViewType::execution_space execution_space; ViewType a; RandomPool rand_pool; - typename ViewType::const_value_type begin,end; + typename ViewType::const_value_type begin, end; - typedef rand Rand; + typedef rand + Rand; fill_random_functor_begin_end(ViewType a_, RandomPool rand_pool_, - typename ViewType::const_value_type begin_, typename ViewType::const_value_type end_): - a(a_),rand_pool(rand_pool_),begin(begin_),end(end_) {} + typename ViewType::const_value_type begin_, + typename ViewType::const_value_type end_) + : a(a_), rand_pool(rand_pool_), begin(begin_), end(end_) {} KOKKOS_INLINE_FUNCTION - void operator() (IndexType i) const { + void operator()(IndexType i) const { typename RandomPool::generator_type gen = rand_pool.get_state(); - for(IndexType j=0;j(a.extent(0))) { - for(IndexType k=0;k(a.extent(1));k++) - for(IndexType l=0;l(a.extent(2));l++) - for(IndexType m=0;m(a.extent(3));m++) - for(IndexType n=0;n(a.extent(4));n++) - for(IndexType o=0;o(a.extent(5));o++) - for(IndexType p=0;p(a.extent(6));p++) - for(IndexType q=0;q(a.extent(7));q++) - a(idx,k,l,m,n,o,p,q) = Rand::draw(gen,begin,end); + for (IndexType j = 0; j < loops; j++) { + const IndexType idx = i * loops + j; + if (idx < static_cast(a.extent(0))) { + for (IndexType k = 0; k < static_cast(a.extent(1)); k++) + for (IndexType l = 0; l < static_cast(a.extent(2)); l++) + for (IndexType m = 0; m < static_cast(a.extent(3)); m++) + for (IndexType n = 0; n < static_cast(a.extent(4)); + n++) + for (IndexType o = 0; o < static_cast(a.extent(5)); + o++) + for (IndexType p = 0; p < static_cast(a.extent(6)); + p++) + for (IndexType q = 0; + q < static_cast(a.extent(7)); q++) + a(idx, k, l, m, n, o, p, q) = Rand::draw(gen, begin, end); } } rand_pool.free_state(gen); } }; -} +} // namespace Impl -template -void fill_random(ViewType a, RandomPool g, typename ViewType::const_value_type range) { +template +void fill_random(ViewType a, RandomPool g, + typename ViewType::const_value_type range) { int64_t LDA = a.extent(0); - if(LDA>0) - parallel_for((LDA+127)/128,Impl::fill_random_functor_range(a,g,range)); + if (LDA > 0) + parallel_for((LDA + 127) / 128, + Impl::fill_random_functor_range( + a, g, range)); } -template -void fill_random(ViewType a, RandomPool g, typename ViewType::const_value_type begin,typename ViewType::const_value_type end ) { +template +void fill_random(ViewType a, RandomPool g, + typename ViewType::const_value_type begin, + typename ViewType::const_value_type end) { int64_t LDA = a.extent(0); - if(LDA>0) - parallel_for((LDA+127)/128,Impl::fill_random_functor_begin_end(a,g,begin,end)); -} + if (LDA > 0) + parallel_for((LDA + 127) / 128, + Impl::fill_random_functor_begin_end( + a, g, begin, end)); } +} // namespace Kokkos #endif diff --git a/lib/kokkos/algorithms/src/Kokkos_Sort.hpp b/lib/kokkos/algorithms/src/Kokkos_Sort.hpp index 7fb8505fe5..b7a988361f 100644 --- a/lib/kokkos/algorithms/src/Kokkos_Sort.hpp +++ b/lib/kokkos/algorithms/src/Kokkos_Sort.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,12 +37,11 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ - #ifndef KOKKOS_SORT_HPP_ #define KOKKOS_SORT_HPP_ @@ -51,125 +51,107 @@ namespace Kokkos { - namespace Impl { +namespace Impl { - template< class DstViewType , class SrcViewType - , int Rank = DstViewType::Rank > - struct CopyOp; +template +struct CopyOp; - template< class DstViewType , class SrcViewType > - struct CopyOp { - KOKKOS_INLINE_FUNCTION - static void copy(DstViewType const& dst, size_t i_dst, - SrcViewType const& src, size_t i_src ) { - dst(i_dst) = src(i_src); - } - }; +template +struct CopyOp { + KOKKOS_INLINE_FUNCTION + static void copy(DstViewType const& dst, size_t i_dst, SrcViewType const& src, + size_t i_src) { + dst(i_dst) = src(i_src); + } +}; - template< class DstViewType , class SrcViewType > - struct CopyOp { - KOKKOS_INLINE_FUNCTION - static void copy(DstViewType const& dst, size_t i_dst, - SrcViewType const& src, size_t i_src ) { - for(int j = 0;j< (int) dst.extent(1); j++) - dst(i_dst,j) = src(i_src,j); - } - }; +template +struct CopyOp { + KOKKOS_INLINE_FUNCTION + static void copy(DstViewType const& dst, size_t i_dst, SrcViewType const& src, + size_t i_src) { + for (int j = 0; j < (int)dst.extent(1); j++) dst(i_dst, j) = src(i_src, j); + } +}; - template< class DstViewType , class SrcViewType > - struct CopyOp { - KOKKOS_INLINE_FUNCTION - static void copy(DstViewType const& dst, size_t i_dst, - SrcViewType const& src, size_t i_src ) { - for(int j = 0; j +struct CopyOp { + KOKKOS_INLINE_FUNCTION + static void copy(DstViewType const& dst, size_t i_dst, SrcViewType const& src, + size_t i_src) { + for (int j = 0; j < dst.extent(1); j++) + for (int k = 0; k < dst.extent(2); k++) + dst(i_dst, j, k) = src(i_src, j, k); } +}; +} // namespace Impl //---------------------------------------------------------------------------- -template< class KeyViewType - , class BinSortOp - , class Space = typename KeyViewType::device_type - , class SizeType = typename KeyViewType::memory_space::size_type - > +template class BinSort { -public: - - template< class DstViewType , class SrcViewType > + public: + template struct copy_functor { + typedef typename SrcViewType::const_type src_view_type; - typedef typename SrcViewType::const_type src_view_type ; + typedef Impl::CopyOp copy_op; - typedef Impl::CopyOp< DstViewType , src_view_type > copy_op ; + DstViewType dst_values; + src_view_type src_values; + int dst_offset; - DstViewType dst_values ; - src_view_type src_values ; - int dst_offset ; - - copy_functor( DstViewType const & dst_values_ - , int const & dst_offset_ - , SrcViewType const & src_values_ - ) - : dst_values( dst_values_ ) - , src_values( src_values_ ) - , dst_offset( dst_offset_ ) - {} + copy_functor(DstViewType const& dst_values_, int const& dst_offset_, + SrcViewType const& src_values_) + : dst_values(dst_values_), + src_values(src_values_), + dst_offset(dst_offset_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int& i) const { - copy_op::copy(dst_values,i+dst_offset,src_values,i); + void operator()(const int& i) const { + copy_op::copy(dst_values, i + dst_offset, src_values, i); } }; - template< class DstViewType - , class PermuteViewType - , class SrcViewType - > + template struct copy_permute_functor { - // If a Kokkos::View then can generate constant random access // otherwise can only use the constant type. - typedef typename std::conditional - < Kokkos::is_view< SrcViewType >::value - , Kokkos::View< typename SrcViewType::const_data_type - , typename SrcViewType::array_layout - , typename SrcViewType::device_type - , Kokkos::MemoryTraits - > - , typename SrcViewType::const_type - >::type src_view_type ; - - typedef typename PermuteViewType::const_type perm_view_type ; - - typedef Impl::CopyOp< DstViewType , src_view_type > copy_op ; - - DstViewType dst_values ; - perm_view_type sort_order ; - src_view_type src_values ; - int src_offset ; - - copy_permute_functor( DstViewType const & dst_values_ - , PermuteViewType const & sort_order_ - , SrcViewType const & src_values_ - , int const & src_offset_ - ) - : dst_values( dst_values_ ) - , sort_order( sort_order_ ) - , src_values( src_values_ ) - , src_offset( src_offset_ ) - {} + typedef typename std::conditional< + Kokkos::is_view::value, + Kokkos::View >, + typename SrcViewType::const_type>::type src_view_type; + + typedef typename PermuteViewType::const_type perm_view_type; + + typedef Impl::CopyOp copy_op; + + DstViewType dst_values; + perm_view_type sort_order; + src_view_type src_values; + int src_offset; + + copy_permute_functor(DstViewType const& dst_values_, + PermuteViewType const& sort_order_, + SrcViewType const& src_values_, int const& src_offset_) + : dst_values(dst_values_), + sort_order(sort_order_), + src_values(src_values_), + src_offset(src_offset_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int& i) const { - copy_op::copy(dst_values,i,src_values,src_offset+sort_order(i)); + void operator()(const int& i) const { + copy_op::copy(dst_values, i, src_values, src_offset + sort_order(i)); } }; - typedef typename Space::execution_space execution_space; + typedef typename Space::execution_space execution_space; typedef BinSortOp bin_op_type; struct bin_count_tag {}; @@ -177,221 +159,236 @@ public: struct bin_binning_tag {}; struct bin_sort_bins_tag {}; -public: - + public: typedef SizeType size_type; typedef size_type value_type; typedef Kokkos::View offset_type; typedef Kokkos::View bin_count_type; - typedef typename KeyViewType::const_type const_key_view_type ; + typedef typename KeyViewType::const_type const_key_view_type; // If a Kokkos::View then can generate constant random access // otherwise can only use the constant type. - typedef typename std::conditional - < Kokkos::is_view< KeyViewType >::value - , Kokkos::View< typename KeyViewType::const_data_type, - typename KeyViewType::array_layout, - typename KeyViewType::device_type, - Kokkos::MemoryTraits > - , const_key_view_type - >::type const_rnd_key_view_type; + typedef typename std::conditional< + Kokkos::is_view::value, + Kokkos::View >, + const_key_view_type>::type const_rnd_key_view_type; typedef typename KeyViewType::non_const_value_type non_const_key_scalar; - typedef typename KeyViewType::const_value_type const_key_scalar; - - typedef Kokkos::View > bin_count_atomic_type ; + typedef typename KeyViewType::const_value_type const_key_scalar; -private: + typedef Kokkos::View > + bin_count_atomic_type; + private: const_key_view_type keys; const_rnd_key_view_type keys_rnd; -public: - - BinSortOp bin_op ; - offset_type bin_offsets ; - bin_count_atomic_type bin_count_atomic ; - bin_count_type bin_count_const ; - offset_type sort_order ; + public: + BinSortOp bin_op; + offset_type bin_offsets; + bin_count_atomic_type bin_count_atomic; + bin_count_type bin_count_const; + offset_type sort_order; - int range_begin ; - int range_end ; - bool sort_within_bins ; - -public: + int range_begin; + int range_end; + bool sort_within_bins; + public: BinSort() {} //---------------------------------------- - // Constructor: takes the keys, the binning_operator and optionally whether to sort within bins (default false) - BinSort( const_key_view_type keys_ - , int range_begin_ - , int range_end_ - , BinSortOp bin_op_ - , bool sort_within_bins_ = false - ) - : keys(keys_) - , keys_rnd(keys_) - , bin_op(bin_op_) - , bin_offsets() - , bin_count_atomic() - , bin_count_const() - , sort_order() - , range_begin( range_begin_ ) - , range_end( range_end_ ) - , sort_within_bins( sort_within_bins_ ) - { - bin_count_atomic = Kokkos::View("Kokkos::SortImpl::BinSortFunctor::bin_count",bin_op.max_bins()); - bin_count_const = bin_count_atomic; - bin_offsets = offset_type(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::bin_offsets"),bin_op.max_bins()); - sort_order = offset_type(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::sort_order"),range_end-range_begin); + // Constructor: takes the keys, the binning_operator and optionally whether to + // sort within bins (default false) + BinSort(const_key_view_type keys_, int range_begin_, int range_end_, + BinSortOp bin_op_, bool sort_within_bins_ = false) + : keys(keys_), + keys_rnd(keys_), + bin_op(bin_op_), + bin_offsets(), + bin_count_atomic(), + bin_count_const(), + sort_order(), + range_begin(range_begin_), + range_end(range_end_), + sort_within_bins(sort_within_bins_) { + bin_count_atomic = Kokkos::View( + "Kokkos::SortImpl::BinSortFunctor::bin_count", bin_op.max_bins()); + bin_count_const = bin_count_atomic; + bin_offsets = + offset_type(ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::bin_offsets"), + bin_op.max_bins()); + sort_order = + offset_type(ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::sort_order"), + range_end - range_begin); } - BinSort( const_key_view_type keys_ - , BinSortOp bin_op_ - , bool sort_within_bins_ = false - ) - : BinSort( keys_ , 0 , keys_.extent(0), bin_op_ , sort_within_bins_ ) {} + BinSort(const_key_view_type keys_, BinSortOp bin_op_, + bool sort_within_bins_ = false) + : BinSort(keys_, 0, keys_.extent(0), bin_op_, sort_within_bins_) {} //---------------------------------------- - // Create the permutation vector, the bin_offset array and the bin_count array. Can be called again if keys changed + // Create the permutation vector, the bin_offset array and the bin_count + // array. Can be called again if keys changed void create_permute_vector() { - const size_t len = range_end - range_begin ; - Kokkos::parallel_for ("Kokkos::Sort::BinCount",Kokkos::RangePolicy (0,len),*this); - Kokkos::parallel_scan("Kokkos::Sort::BinOffset",Kokkos::RangePolicy (0,bin_op.max_bins()) ,*this); - - Kokkos::deep_copy(bin_count_atomic,0); - Kokkos::parallel_for ("Kokkos::Sort::BinBinning",Kokkos::RangePolicy (0,len),*this); - - if(sort_within_bins) - Kokkos::parallel_for ("Kokkos::Sort::BinSort",Kokkos::RangePolicy(0,bin_op.max_bins()) ,*this); + const size_t len = range_end - range_begin; + Kokkos::parallel_for( + "Kokkos::Sort::BinCount", + Kokkos::RangePolicy(0, len), *this); + Kokkos::parallel_scan("Kokkos::Sort::BinOffset", + Kokkos::RangePolicy( + 0, bin_op.max_bins()), + *this); + + Kokkos::deep_copy(bin_count_atomic, 0); + Kokkos::parallel_for( + "Kokkos::Sort::BinBinning", + Kokkos::RangePolicy(0, len), *this); + + if (sort_within_bins) + Kokkos::parallel_for( + "Kokkos::Sort::BinSort", + Kokkos::RangePolicy( + 0, bin_op.max_bins()), + *this); } - // Sort a subset of a view with respect to the first dimension using the permutation array - template - void sort( ValuesViewType const & values - , int values_range_begin - , int values_range_end) const - { - typedef - Kokkos::View< typename ValuesViewType::data_type, - typename ValuesViewType::array_layout, - typename ValuesViewType::device_type > - scratch_view_type ; - - const size_t len = range_end - range_begin ; - const size_t values_len = values_range_end - values_range_begin ; + // Sort a subset of a view with respect to the first dimension using the + // permutation array + template + void sort(ValuesViewType const& values, int values_range_begin, + int values_range_end) const { + typedef Kokkos::View + scratch_view_type; + + const size_t len = range_end - range_begin; + const size_t values_len = values_range_end - values_range_begin; if (len != values_len) { - Kokkos::abort("BinSort::sort: values range length != permutation vector length"); + Kokkos::abort( + "BinSort::sort: values range length != permutation vector length"); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - scratch_view_type - sorted_values(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::sorted_values"), - len, - values.extent(1), - values.extent(2), - values.extent(3), - values.extent(4), - values.extent(5), - values.extent(6), - values.extent(7)); + scratch_view_type sorted_values( + ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::sorted_values"), + len, values.extent(1), values.extent(2), values.extent(3), + values.extent(4), values.extent(5), values.extent(6), values.extent(7)); #else - scratch_view_type - sorted_values(ViewAllocateWithoutInitializing("Kokkos::SortImpl::BinSortFunctor::sorted_values"), - values.rank_dynamic > 0 ? len : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 1 ? values.extent(1) : KOKKOS_IMPL_CTOR_DEFAULT_ARG , - values.rank_dynamic > 2 ? values.extent(2) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 3 ? values.extent(3) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 4 ? values.extent(4) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 5 ? values.extent(5) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 6 ? values.extent(6) : KOKKOS_IMPL_CTOR_DEFAULT_ARG, - values.rank_dynamic > 7 ? values.extent(7) : KOKKOS_IMPL_CTOR_DEFAULT_ARG); + scratch_view_type sorted_values( + ViewAllocateWithoutInitializing( + "Kokkos::SortImpl::BinSortFunctor::sorted_values"), + values.rank_dynamic > 0 ? len : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 1 ? values.extent(1) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 2 ? values.extent(2) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 3 ? values.extent(3) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 4 ? values.extent(4) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 5 ? values.extent(5) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 6 ? values.extent(6) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + values.rank_dynamic > 7 ? values.extent(7) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG); #endif { - copy_permute_functor< scratch_view_type /* DstViewType */ - , offset_type /* PermuteViewType */ - , ValuesViewType /* SrcViewType */ - > - functor( sorted_values , sort_order , values, values_range_begin - range_begin ); - - parallel_for("Kokkos::Sort::CopyPermute", Kokkos::RangePolicy(0,len),functor); + copy_permute_functor + functor(sorted_values, sort_order, values, + values_range_begin - range_begin); + + parallel_for("Kokkos::Sort::CopyPermute", + Kokkos::RangePolicy(0, len), functor); } { - copy_functor< ValuesViewType , scratch_view_type > - functor( values , range_begin , sorted_values ); + copy_functor functor( + values, range_begin, sorted_values); - parallel_for("Kokkos::Sort::Copy", Kokkos::RangePolicy(0,len),functor); + parallel_for("Kokkos::Sort::Copy", + Kokkos::RangePolicy(0, len), functor); } Kokkos::fence(); } - template - void sort( ValuesViewType const & values ) const - { - this->sort( values, 0, /*values.extent(0)*/ range_end - range_begin ); + template + void sort(ValuesViewType const& values) const { + this->sort(values, 0, /*values.extent(0)*/ range_end - range_begin); } // Get the permutation vector KOKKOS_INLINE_FUNCTION - offset_type get_permute_vector() const { return sort_order;} + offset_type get_permute_vector() const { return sort_order; } // Get the start offsets for each bin KOKKOS_INLINE_FUNCTION - offset_type get_bin_offsets() const { return bin_offsets;} + offset_type get_bin_offsets() const { return bin_offsets; } // Get the count for each bin KOKKOS_INLINE_FUNCTION - bin_count_type get_bin_count() const {return bin_count_const;} - -public: + bin_count_type get_bin_count() const { return bin_count_const; } + public: KOKKOS_INLINE_FUNCTION - void operator() (const bin_count_tag& tag, const int& i) const { - const int j = range_begin + i ; + void operator()(const bin_count_tag& tag, const int& i) const { + const int j = range_begin + i; bin_count_atomic(bin_op.bin(keys, j))++; } KOKKOS_INLINE_FUNCTION - void operator() (const bin_offset_tag& tag, const int& i, value_type& offset, const bool& final) const { - if(final) { + void operator()(const bin_offset_tag& tag, const int& i, value_type& offset, + const bool& final) const { + if (final) { bin_offsets(i) = offset; } - offset+=bin_count_const(i); + offset += bin_count_const(i); } KOKKOS_INLINE_FUNCTION - void operator() (const bin_binning_tag& tag, const int& i) const { - const int j = range_begin + i ; - const int bin = bin_op.bin(keys,j); + void operator()(const bin_binning_tag& tag, const int& i) const { + const int j = range_begin + i; + const int bin = bin_op.bin(keys, j); const int count = bin_count_atomic(bin)++; - sort_order(bin_offsets(bin) + count) = j ; + sort_order(bin_offsets(bin) + count) = j; } KOKKOS_INLINE_FUNCTION - void operator() (const bin_sort_bins_tag& tag, const int&i ) const { + void operator()(const bin_sort_bins_tag& tag, const int& i) const { auto bin_size = bin_count_const(i); if (bin_size <= 1) return; - int upper_bound = bin_offsets(i)+bin_size; - bool sorted = false; - while(!sorted) { - sorted = true; + int upper_bound = bin_offsets(i) + bin_size; + bool sorted = false; + while (!sorted) { + sorted = true; int old_idx = sort_order(bin_offsets(i)); int new_idx; - for(int k=bin_offsets(i)+1; k +template struct BinOp1D { int max_bins_; double mul_; typename KeyViewType::const_value_type range_; typename KeyViewType::const_value_type min_; - BinOp1D():max_bins_(0),mul_(0.0), - range_(typename KeyViewType::const_value_type()), - min_(typename KeyViewType::const_value_type()) {} + BinOp1D() + : max_bins_(0), + mul_(0.0), + range_(typename KeyViewType::const_value_type()), + min_(typename KeyViewType::const_value_type()) {} - //Construct BinOp with number of bins, minimum value and maxuimum value + // Construct BinOp with number of bins, minimum value and maxuimum value BinOp1D(int max_bins__, typename KeyViewType::const_value_type min, - typename KeyViewType::const_value_type max ) - :max_bins_(max_bins__+1),mul_(1.0*max_bins__/(max-min)),range_(max-min),min_(min) {} - - //Determine bin index from key value - template - KOKKOS_INLINE_FUNCTION - int bin(ViewType& keys, const int& i) const { - return int(mul_*(keys(i)-min_)); + typename KeyViewType::const_value_type max) + : max_bins_(max_bins__ + 1), + mul_(1.0 * max_bins__ / (max - min)), + range_(max - min), + min_(min) {} + + // Determine bin index from key value + template + KOKKOS_INLINE_FUNCTION int bin(ViewType& keys, const int& i) const { + return int(mul_ * (keys(i) - min_)); } - //Return maximum bin index + 1 + // Return maximum bin index + 1 KOKKOS_INLINE_FUNCTION - int max_bins() const { - return max_bins_; - } + int max_bins() const { return max_bins_; } - //Compare to keys within a bin if true new_val will be put before old_val - template - KOKKOS_INLINE_FUNCTION - bool operator()(ViewType& keys, iType1& i1, iType2& i2) const { - return keys(i1) + KOKKOS_INLINE_FUNCTION bool operator()(ViewType& keys, iType1& i1, + iType2& i2) const { + return keys(i1) < keys(i2); } }; -template +template struct BinOp3D { int max_bins_[3]; double mul_[3]; @@ -450,43 +449,42 @@ struct BinOp3D { BinOp3D() {} BinOp3D(int max_bins__[], typename KeyViewType::const_value_type min[], - typename KeyViewType::const_value_type max[] ) - { + typename KeyViewType::const_value_type max[]) { max_bins_[0] = max_bins__[0]; max_bins_[1] = max_bins__[1]; max_bins_[2] = max_bins__[2]; - mul_[0] = 1.0*max_bins__[0]/(max[0]-min[0]); - mul_[1] = 1.0*max_bins__[1]/(max[1]-min[1]); - mul_[2] = 1.0*max_bins__[2]/(max[2]-min[2]); - range_[0] = max[0]-min[0]; - range_[1] = max[1]-min[1]; - range_[2] = max[2]-min[2]; - min_[0] = min[0]; - min_[1] = min[1]; - min_[2] = min[2]; + mul_[0] = 1.0 * max_bins__[0] / (max[0] - min[0]); + mul_[1] = 1.0 * max_bins__[1] / (max[1] - min[1]); + mul_[2] = 1.0 * max_bins__[2] / (max[2] - min[2]); + range_[0] = max[0] - min[0]; + range_[1] = max[1] - min[1]; + range_[2] = max[2] - min[2]; + min_[0] = min[0]; + min_[1] = min[1]; + min_[2] = min[2]; } - template - KOKKOS_INLINE_FUNCTION - int bin(ViewType& keys, const int& i) const { - return int( (((int(mul_[0]*(keys(i,0)-min_[0]))*max_bins_[1]) + - int(mul_[1]*(keys(i,1)-min_[1])))*max_bins_[2]) + - int(mul_[2]*(keys(i,2)-min_[2]))); - } - - KOKKOS_INLINE_FUNCTION - int max_bins() const { - return max_bins_[0]*max_bins_[1]*max_bins_[2]; + template + KOKKOS_INLINE_FUNCTION int bin(ViewType& keys, const int& i) const { + return int((((int(mul_[0] * (keys(i, 0) - min_[0])) * max_bins_[1]) + + int(mul_[1] * (keys(i, 1) - min_[1]))) * + max_bins_[2]) + + int(mul_[2] * (keys(i, 2) - min_[2]))); } - template KOKKOS_INLINE_FUNCTION - bool operator()(ViewType& keys, iType1& i1 , iType2& i2) const { - if (keys(i1,0)>keys(i2,0)) return true; - else if (keys(i1,0)==keys(i2,0)) { - if (keys(i1,1)>keys(i2,1)) return true; - else if (keys(i1,1)==keys(i2,1)) { - if (keys(i1,2)>keys(i2,2)) return true; + int max_bins() const { return max_bins_[0] * max_bins_[1] * max_bins_[2]; } + + template + KOKKOS_INLINE_FUNCTION bool operator()(ViewType& keys, iType1& i1, + iType2& i2) const { + if (keys(i1, 0) > keys(i2, 0)) + return true; + else if (keys(i1, 0) == keys(i2, 0)) { + if (keys(i1, 1) > keys(i2, 1)) + return true; + else if (keys(i1, 1) == keys(i2, 1)) { + if (keys(i1, 2) > keys(i2, 2)) return true; } } return false; @@ -495,85 +493,80 @@ struct BinOp3D { namespace Impl { -template +template bool try_std_sort(ViewType view) { - bool possible = true; - size_t stride[8] = { view.stride_0() - , view.stride_1() - , view.stride_2() - , view.stride_3() - , view.stride_4() - , view.stride_5() - , view.stride_6() - , view.stride_7() - }; - possible = possible && std::is_same::value; - possible = possible && (ViewType::Rank == 1); - possible = possible && (stride[0] == 1); - if(possible) { - std::sort(view.data(),view.data()+view.extent(0)); + bool possible = true; + size_t stride[8] = {view.stride_0(), view.stride_1(), view.stride_2(), + view.stride_3(), view.stride_4(), view.stride_5(), + view.stride_6(), view.stride_7()}; + possible = possible && + std::is_same::value; + possible = possible && (ViewType::Rank == 1); + possible = possible && (stride[0] == 1); + if (possible) { + std::sort(view.data(), view.data() + view.extent(0)); } return possible; } -template +template struct min_max_functor { - typedef Kokkos::MinMaxScalar minmax_scalar; + typedef Kokkos::MinMaxScalar + minmax_scalar; ViewType view; - min_max_functor(const ViewType& view_):view(view_) {} + min_max_functor(const ViewType& view_) : view(view_) {} KOKKOS_INLINE_FUNCTION - void operator() (const size_t& i, minmax_scalar& minmax) const { - if(view(i) < minmax.min_val) minmax.min_val = view(i); - if(view(i) > minmax.max_val) minmax.max_val = view(i); + void operator()(const size_t& i, minmax_scalar& minmax) const { + if (view(i) < minmax.min_val) minmax.min_val = view(i); + if (view(i) > minmax.max_val) minmax.max_val = view(i); } }; -} +} // namespace Impl -template -void sort( ViewType const & view , bool const always_use_kokkos_sort = false) -{ - if(!always_use_kokkos_sort) { - if(Impl::try_std_sort(view)) return; +template +void sort(ViewType const& view, bool const always_use_kokkos_sort = false) { + if (!always_use_kokkos_sort) { + if (Impl::try_std_sort(view)) return; } typedef BinOp1D CompType; Kokkos::MinMaxScalar result; Kokkos::MinMax reducer(result); - parallel_reduce("Kokkos::Sort::FindExtent",Kokkos::RangePolicy(0,view.extent(0)), - Impl::min_max_functor(view),reducer); - if(result.min_val == result.max_val) return; - BinSort bin_sort(view,CompType(view.extent(0)/2,result.min_val,result.max_val),true); + parallel_reduce("Kokkos::Sort::FindExtent", + Kokkos::RangePolicy( + 0, view.extent(0)), + Impl::min_max_functor(view), reducer); + if (result.min_val == result.max_val) return; + BinSort bin_sort( + view, CompType(view.extent(0) / 2, result.min_val, result.max_val), true); bin_sort.create_permute_vector(); bin_sort.sort(view); } -template -void sort( ViewType view - , size_t const begin - , size_t const end - ) -{ - typedef Kokkos::RangePolicy range_policy ; +template +void sort(ViewType view, size_t const begin, size_t const end) { + typedef Kokkos::RangePolicy range_policy; typedef BinOp1D CompType; Kokkos::MinMaxScalar result; Kokkos::MinMax reducer(result); - parallel_reduce("Kokkos::Sort::FindExtent", range_policy( begin , end ) - , Impl::min_max_functor(view),reducer ); + parallel_reduce("Kokkos::Sort::FindExtent", range_policy(begin, end), + Impl::min_max_functor(view), reducer); - if(result.min_val == result.max_val) return; + if (result.min_val == result.max_val) return; - BinSort - bin_sort(view,begin,end,CompType((end-begin)/2,result.min_val,result.max_val),true); + BinSort bin_sort( + view, begin, end, + CompType((end - begin) / 2, result.min_val, result.max_val), true); bin_sort.create_permute_vector(); - bin_sort.sort(view,begin,end); + bin_sort.sort(view, begin, end); } -} +} // namespace Kokkos #endif diff --git a/lib/kokkos/algorithms/unit_tests/CMakeLists.txt b/lib/kokkos/algorithms/unit_tests/CMakeLists.txt index e238b37c8e..6fb08ce2ed 100644 --- a/lib/kokkos/algorithms/unit_tests/CMakeLists.txt +++ b/lib/kokkos/algorithms/unit_tests/CMakeLists.txt @@ -1,18 +1,12 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) +#Leave these here for now - I don't need transitive deps anyway +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() -ENDIF() SET(GTEST_SOURCE_DIR ${${PARENT_PACKAGE_NAME}_SOURCE_DIR}/tpls/gtest) -INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR}) # mfh 03 Nov 2017: The gtest library used here must have a different # name than that of the gtest library built in KokkosCore. We can't @@ -20,23 +14,20 @@ INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR}) # possible to build only (e.g.,) KokkosAlgorithms tests, without # building KokkosCore tests. -SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DGTEST_HAS_PTHREAD=0") -TRIBITS_ADD_LIBRARY( +KOKKOS_ADD_TEST_LIBRARY( kokkosalgorithms_gtest HEADERS ${GTEST_SOURCE_DIR}/gtest/gtest.h SOURCES ${GTEST_SOURCE_DIR}/gtest/gtest-all.cc - TESTONLY - ) +) +KOKKOS_TARGET_COMPILE_DEFINITIONS(kokkosalgorithms_gtest PUBLIC "-DGTEST_HAS_PTHREAD=0") SET(SOURCES UnitTestMain.cpp TestCuda.cpp ) -SET(LIBRARIES kokkoscore) - -IF(Kokkos_ENABLE_OpenMP) +IF(Kokkos_ENABLE_OPENMP) LIST( APPEND SOURCES TestOpenMP.cpp ) @@ -48,23 +39,19 @@ IF(Kokkos_ENABLE_HPX) ) ENDIF() -IF(Kokkos_ENABLE_Serial) +IF(Kokkos_ENABLE_SERIAL) LIST( APPEND SOURCES TestSerial.cpp ) ENDIF() -IF(Kokkos_ENABLE_Pthread) +IF(Kokkos_ENABLE_PTHREAD) LIST( APPEND SOURCES TestThreads.cpp ) ENDIF() -TRIBITS_ADD_EXECUTABLE_AND_TEST( +KOKKOS_ADD_EXECUTABLE_AND_TEST( UnitTest SOURCES ${SOURCES} - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkosalgorithms_gtest ${TEST_LINK_TARGETS} - ) +) diff --git a/lib/kokkos/algorithms/unit_tests/TestCuda.cpp b/lib/kokkos/algorithms/unit_tests/TestCuda.cpp index 86fdccd0e7..ab727b0326 100644 --- a/lib/kokkos/algorithms/unit_tests/TestCuda.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestCuda.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,51 +58,31 @@ namespace Test { -class cuda : public ::testing::Test { -protected: - static void SetUpTestCase() - { - } - static void TearDownTestCase() - { - } -}; - -void cuda_test_random_xorshift64( int num_draws ) -{ +void cuda_test_random_xorshift64(int num_draws) { Impl::test_random >(num_draws); } -void cuda_test_random_xorshift1024( int num_draws ) -{ +void cuda_test_random_xorshift1024(int num_draws) { Impl::test_random >(num_draws); } +#define CUDA_RANDOM_XORSHIFT64(num_draws) \ + TEST(cuda, Random_XorShift64) { cuda_test_random_xorshift64(num_draws); } -#define CUDA_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( cuda, Random_XorShift64 ) { \ - cuda_test_random_xorshift64(num_draws); \ - } - -#define CUDA_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( cuda, Random_XorShift1024 ) { \ - cuda_test_random_xorshift1024(num_draws); \ - } +#define CUDA_RANDOM_XORSHIFT1024(num_draws) \ + TEST(cuda, Random_XorShift1024) { cuda_test_random_xorshift1024(num_draws); } -#define CUDA_SORT_UNSIGNED( size ) \ - TEST_F( cuda, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Cuda, unsigned >(size); \ - } +#define CUDA_SORT_UNSIGNED(size) \ + TEST(cuda, SortUnsigned) { Impl::test_sort(size); } -CUDA_RANDOM_XORSHIFT64( 132141141 ) -CUDA_RANDOM_XORSHIFT1024( 52428813 ) +CUDA_RANDOM_XORSHIFT64(132141141) +CUDA_RANDOM_XORSHIFT1024(52428813) CUDA_SORT_UNSIGNED(171) #undef CUDA_RANDOM_XORSHIFT64 #undef CUDA_RANDOM_XORSHIFT1024 #undef CUDA_SORT_UNSIGNED -} +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTCUDA_PREVENT_LINK_ERROR() {} -#endif /* #ifdef KOKKOS_ENABLE_CUDA */ - +#endif /* #ifdef KOKKOS_ENABLE_CUDA */ diff --git a/lib/kokkos/algorithms/unit_tests/TestHPX.cpp b/lib/kokkos/algorithms/unit_tests/TestHPX.cpp index e5b7dbdb7a..2981e97945 100644 --- a/lib/kokkos/algorithms/unit_tests/TestHPX.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestHPX.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,7 +42,6 @@ //@HEADER */ - #include #ifdef KOKKOS_ENABLE_HPX @@ -55,42 +55,33 @@ namespace Test { -class hpx : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; - } - - static void TearDownTestCase() - { +#define HPX_RANDOM_XORSHIFT64(num_draws) \ + TEST(hpx, Random_XorShift64) { \ + Impl::test_random< \ + Kokkos::Random_XorShift64_Pool >( \ + num_draws); \ } -}; -#define HPX_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( hpx, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define HPX_RANDOM_XORSHIFT1024(num_draws) \ + TEST(hpx, Random_XorShift1024) { \ + Impl::test_random< \ + Kokkos::Random_XorShift1024_Pool >( \ + num_draws); \ } -#define HPX_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( hpx, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ +#define HPX_SORT_UNSIGNED(size) \ + TEST(hpx, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define HPX_SORT_UNSIGNED( size ) \ - TEST_F( hpx, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Experimental::HPX, unsigned >(size); \ - } - -HPX_RANDOM_XORSHIFT64( 10240000 ) -HPX_RANDOM_XORSHIFT1024( 10130144 ) +HPX_RANDOM_XORSHIFT64(10240000) +HPX_RANDOM_XORSHIFT1024(10130144) HPX_SORT_UNSIGNED(171) #undef HPX_RANDOM_XORSHIFT64 #undef HPX_RANDOM_XORSHIFT1024 #undef HPX_SORT_UNSIGNED -} // namespace test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTHPX_PREVENT_LINK_ERROR() {} #endif - diff --git a/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp b/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp index c4ddde7b7f..3a9e306014 100644 --- a/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestOpenMP.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,7 +42,6 @@ //@HEADER */ - #include #ifdef KOKKOS_ENABLE_OPENMP @@ -55,42 +55,31 @@ namespace Test { -class openmp : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; - } - - static void TearDownTestCase() - { +#define OPENMP_RANDOM_XORSHIFT64(num_draws) \ + TEST(openmp, Random_XorShift64) { \ + Impl::test_random >( \ + num_draws); \ } -}; -#define OPENMP_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( openmp, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define OPENMP_RANDOM_XORSHIFT1024(num_draws) \ + TEST(openmp, Random_XorShift1024) { \ + Impl::test_random >( \ + num_draws); \ } -#define OPENMP_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( openmp, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ +#define OPENMP_SORT_UNSIGNED(size) \ + TEST(openmp, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define OPENMP_SORT_UNSIGNED( size ) \ - TEST_F( openmp, SortUnsigned ) { \ - Impl::test_sort< Kokkos::OpenMP, unsigned >(size); \ - } - -OPENMP_RANDOM_XORSHIFT64( 10240000 ) -OPENMP_RANDOM_XORSHIFT1024( 10130144 ) +OPENMP_RANDOM_XORSHIFT64(10240000) +OPENMP_RANDOM_XORSHIFT1024(10130144) OPENMP_SORT_UNSIGNED(171) #undef OPENMP_RANDOM_XORSHIFT64 #undef OPENMP_RANDOM_XORSHIFT1024 #undef OPENMP_SORT_UNSIGNED -} // namespace test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTOPENMP_PREVENT_LINK_ERROR() {} #endif - diff --git a/lib/kokkos/algorithms/unit_tests/TestROCm.cpp b/lib/kokkos/algorithms/unit_tests/TestROCm.cpp index 15179509bb..29814cca3e 100644 --- a/lib/kokkos/algorithms/unit_tests/TestROCm.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestROCm.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,52 +58,35 @@ namespace Test { -class rocm : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; - } - static void TearDownTestCase() - { - } -}; - -void rocm_test_random_xorshift64( int num_draws ) -{ - Impl::test_random >(num_draws); +void rocm_test_random_xorshift64(int num_draws) { + Impl::test_random< + Kokkos::Random_XorShift64_Pool >(num_draws); } -void rocm_test_random_xorshift1024( int num_draws ) -{ - Impl::test_random >(num_draws); +void rocm_test_random_xorshift1024(int num_draws) { + Impl::test_random< + Kokkos::Random_XorShift1024_Pool >(num_draws); } +#define ROCM_RANDOM_XORSHIFT64(num_draws) \ + TEST(rocm, Random_XorShift64) { rocm_test_random_xorshift64(num_draws); } -#define ROCM_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( rocm, Random_XorShift64 ) { \ - rocm_test_random_xorshift64(num_draws); \ - } - -#define ROCM_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( rocm, Random_XorShift1024 ) { \ - rocm_test_random_xorshift1024(num_draws); \ - } +#define ROCM_RANDOM_XORSHIFT1024(num_draws) \ + TEST(rocm, Random_XorShift1024) { rocm_test_random_xorshift1024(num_draws); } -#define ROCM_SORT_UNSIGNED( size ) \ - TEST_F( rocm, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Experimental::ROCm, unsigned >(size); \ +#define ROCM_SORT_UNSIGNED(size) \ + TEST(rocm, SortUnsigned) { \ + Impl::test_sort(size); \ } -ROCM_RANDOM_XORSHIFT64( 132141141 ) -ROCM_RANDOM_XORSHIFT1024( 52428813 ) +ROCM_RANDOM_XORSHIFT64(132141141) +ROCM_RANDOM_XORSHIFT1024(52428813) ROCM_SORT_UNSIGNED(171) #undef ROCM_RANDOM_XORSHIFT64 #undef ROCM_RANDOM_XORSHIFT1024 #undef ROCM_SORT_UNSIGNED -} +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTROCM_PREVENT_LINK_ERROR() {} -#endif /* #ifdef KOKKOS_ENABLE_ROCM */ - +#endif /* #ifdef KOKKOS_ENABLE_ROCM */ diff --git a/lib/kokkos/algorithms/unit_tests/TestRandom.hpp b/lib/kokkos/algorithms/unit_tests/TestRandom.hpp index 73bd416f2a..bc55ebfad3 100644 --- a/lib/kokkos/algorithms/unit_tests/TestRandom.hpp +++ b/lib/kokkos/algorithms/unit_tests/TestRandom.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -54,18 +55,19 @@ namespace Test { -namespace Impl{ +namespace Impl { // This test runs the random number generators and uses some statistic tests to // check the 'goodness' of the random numbers: // (i) mean: the mean is expected to be 0.5*RAND_MAX // (ii) variance: the variance is 1/3*mean*mean // (iii) covariance: the covariance is 0 -// (iv) 1-tupledistr: the mean, variance and covariance of a 1D Histrogram of random numbers -// (v) 3-tupledistr: the mean, variance and covariance of a 3D Histrogram of random numbers +// (iv) 1-tupledistr: the mean, variance and covariance of a 1D Histrogram +// of random numbers (v) 3-tupledistr: the mean, variance and covariance of +// a 3D Histrogram of random numbers #define HIST_DIM3D 24 -#define HIST_DIM1D (HIST_DIM3D*HIST_DIM3D*HIST_DIM3D) +#define HIST_DIM1D (HIST_DIM3D * HIST_DIM3D * HIST_DIM3D) struct RandomProperties { uint64_t count; @@ -77,37 +79,37 @@ struct RandomProperties { KOKKOS_INLINE_FUNCTION RandomProperties() { - count = 0; - mean = 0.0; - variance = 0.0; + count = 0; + mean = 0.0; + variance = 0.0; covariance = 0.0; - min = 1e64; - max = -1e64; + min = 1e64; + max = -1e64; } KOKKOS_INLINE_FUNCTION RandomProperties& operator+=(const RandomProperties& add) { - count += add.count; - mean += add.mean; - variance += add.variance; + count += add.count; + mean += add.mean; + variance += add.variance; covariance += add.covariance; - min = add.minmax?add.max:max; + min = add.min < min ? add.min : min; + max = add.max > max ? add.max : max; return *this; } KOKKOS_INLINE_FUNCTION void operator+=(const volatile RandomProperties& add) volatile { - count += add.count; - mean += add.mean; - variance += add.variance; + count += add.count; + mean += add.mean; + variance += add.variance; covariance += add.covariance; - min = add.minmax?add.max:max; + min = add.min < min ? add.min : min; + max = add.max > max ? add.max : max; } }; -template +template struct test_random_functor { typedef typename GeneratorPool::generator_type rnd_type; @@ -123,38 +125,40 @@ struct test_random_functor { // implementations might violate this upper bound, due to rounding // error. Just in case, we leave an extra space at the end of each // dimension, in the View types below. - typedef Kokkos::View type_1d; + typedef Kokkos::View + type_1d; type_1d density_1d; - typedef Kokkos::View type_3d; + typedef Kokkos::View + type_3d; type_3d density_3d; - test_random_functor (GeneratorPool rand_pool_, type_1d d1d, type_3d d3d) : - rand_pool (rand_pool_), - mean (0.5*Kokkos::rand::max ()), - density_1d (d1d), - density_3d (d3d) - {} + test_random_functor(GeneratorPool rand_pool_, type_1d d1d, type_3d d3d) + : rand_pool(rand_pool_), + mean(0.5 * Kokkos::rand::max()), + density_1d(d1d), + density_3d(d3d) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, RandomProperties& prop) const { + void operator()(int i, RandomProperties& prop) const { using Kokkos::atomic_fetch_add; rnd_type rand_gen = rand_pool.get_state(); for (int k = 0; k < 1024; ++k) { - const Scalar tmp = Kokkos::rand::draw(rand_gen); + const Scalar tmp = Kokkos::rand::draw(rand_gen); prop.count++; prop.mean += tmp; - prop.variance += (tmp-mean)*(tmp-mean); - const Scalar tmp2 = Kokkos::rand::draw(rand_gen); + prop.variance += (tmp - mean) * (tmp - mean); + const Scalar tmp2 = Kokkos::rand::draw(rand_gen); prop.count++; prop.mean += tmp2; - prop.variance += (tmp2-mean)*(tmp2-mean); - prop.covariance += (tmp-mean)*(tmp2-mean); - const Scalar tmp3 = Kokkos::rand::draw(rand_gen); + prop.variance += (tmp2 - mean) * (tmp2 - mean); + prop.covariance += (tmp - mean) * (tmp2 - mean); + const Scalar tmp3 = Kokkos::rand::draw(rand_gen); prop.count++; prop.mean += tmp3; - prop.variance += (tmp3-mean)*(tmp3-mean); - prop.covariance += (tmp2-mean)*(tmp3-mean); + prop.variance += (tmp3 - mean) * (tmp3 - mean); + prop.covariance += (tmp2 - mean) * (tmp3 - mean); // NOTE (mfh 03 Nov 2014): Kokkos::rand::max() is supposed to // define an exclusive upper bound on the range of random @@ -169,26 +173,32 @@ struct test_random_functor { // returns values of max(), the histograms will still catch this // indirectly, since none of the other values will be filled in. - const Scalar theMax = Kokkos::rand::max (); - - const uint64_t ind1_1d = static_cast (1.0 * HIST_DIM1D * tmp / theMax); - const uint64_t ind2_1d = static_cast (1.0 * HIST_DIM1D * tmp2 / theMax); - const uint64_t ind3_1d = static_cast (1.0 * HIST_DIM1D * tmp3 / theMax); - - const uint64_t ind1_3d = static_cast (1.0 * HIST_DIM3D * tmp / theMax); - const uint64_t ind2_3d = static_cast (1.0 * HIST_DIM3D * tmp2 / theMax); - const uint64_t ind3_3d = static_cast (1.0 * HIST_DIM3D * tmp3 / theMax); - - atomic_fetch_add (&density_1d(ind1_1d), 1); - atomic_fetch_add (&density_1d(ind2_1d), 1); - atomic_fetch_add (&density_1d(ind3_1d), 1); - atomic_fetch_add (&density_3d(ind1_3d, ind2_3d, ind3_3d), 1); + const Scalar theMax = Kokkos::rand::max(); + + const uint64_t ind1_1d = + static_cast(1.0 * HIST_DIM1D * tmp / theMax); + const uint64_t ind2_1d = + static_cast(1.0 * HIST_DIM1D * tmp2 / theMax); + const uint64_t ind3_1d = + static_cast(1.0 * HIST_DIM1D * tmp3 / theMax); + + const uint64_t ind1_3d = + static_cast(1.0 * HIST_DIM3D * tmp / theMax); + const uint64_t ind2_3d = + static_cast(1.0 * HIST_DIM3D * tmp2 / theMax); + const uint64_t ind3_3d = + static_cast(1.0 * HIST_DIM3D * tmp3 / theMax); + + atomic_fetch_add(&density_1d(ind1_1d), 1); + atomic_fetch_add(&density_1d(ind2_1d), 1); + atomic_fetch_add(&density_1d(ind3_1d), 1); + atomic_fetch_add(&density_3d(ind1_3d, ind2_3d, ind3_3d), 1); } rand_pool.free_state(rand_gen); } }; -template +template struct test_histogram1d_functor { typedef RandomProperties value_type; typedef typename DeviceType::execution_space execution_space; @@ -200,34 +210,29 @@ struct test_histogram1d_functor { // implementations might violate this upper bound, due to rounding // error. Just in case, we leave an extra space at the end of each // dimension, in the View type below. - typedef Kokkos::View type_1d; + typedef Kokkos::View type_1d; type_1d density_1d; double mean; - test_histogram1d_functor (type_1d d1d, int num_draws) : - density_1d (d1d), - mean (1.0*num_draws/HIST_DIM1D*3) - { - } + test_histogram1d_functor(type_1d d1d, int num_draws) + : density_1d(d1d), mean(1.0 * num_draws / HIST_DIM1D * 3) {} - KOKKOS_INLINE_FUNCTION void - operator() (const typename memory_space::size_type i, - RandomProperties& prop) const - { + KOKKOS_INLINE_FUNCTION void operator()( + const typename memory_space::size_type i, RandomProperties& prop) const { typedef typename memory_space::size_type size_type; const double count = density_1d(i); prop.mean += count; prop.variance += 1.0 * (count - mean) * (count - mean); - //prop.covariance += 1.0*count*count; + // prop.covariance += 1.0*count*count; prop.min = count < prop.min ? count : prop.min; prop.max = count > prop.max ? count : prop.max; - if (i < static_cast (HIST_DIM1D-1)) { - prop.covariance += (count - mean) * (density_1d(i+1) - mean); + if (i < static_cast(HIST_DIM1D - 1)) { + prop.covariance += (count - mean) * (density_1d(i + 1) - mean); } } }; -template +template struct test_histogram3d_functor { typedef RandomProperties value_type; typedef typename DeviceType::execution_space execution_space; @@ -239,29 +244,28 @@ struct test_histogram3d_functor { // implementations might violate this upper bound, due to rounding // error. Just in case, we leave an extra space at the end of each // dimension, in the View type below. - typedef Kokkos::View type_3d; + typedef Kokkos::View + type_3d; type_3d density_3d; double mean; - test_histogram3d_functor (type_3d d3d, int num_draws) : - density_3d (d3d), - mean (1.0*num_draws/HIST_DIM1D) - {} + test_histogram3d_functor(type_3d d3d, int num_draws) + : density_3d(d3d), mean(1.0 * num_draws / HIST_DIM1D) {} - KOKKOS_INLINE_FUNCTION void - operator() (const typename memory_space::size_type i, - RandomProperties& prop) const - { + KOKKOS_INLINE_FUNCTION void operator()( + const typename memory_space::size_type i, RandomProperties& prop) const { typedef typename memory_space::size_type size_type; - const double count = density_3d(i/(HIST_DIM3D*HIST_DIM3D), - (i % (HIST_DIM3D*HIST_DIM3D))/HIST_DIM3D, - i % HIST_DIM3D); + const double count = density_3d( + i / (HIST_DIM3D * HIST_DIM3D), + (i % (HIST_DIM3D * HIST_DIM3D)) / HIST_DIM3D, i % HIST_DIM3D); prop.mean += count; prop.variance += (count - mean) * (count - mean); - if (i < static_cast (HIST_DIM1D-1)) { - const double count_next = density_3d((i+1)/(HIST_DIM3D*HIST_DIM3D), - ((i+1)%(HIST_DIM3D*HIST_DIM3D))/HIST_DIM3D, - (i+1)%HIST_DIM3D); + if (i < static_cast(HIST_DIM1D - 1)) { + const double count_next = + density_3d((i + 1) / (HIST_DIM3D * HIST_DIM3D), + ((i + 1) % (HIST_DIM3D * HIST_DIM3D)) / HIST_DIM3D, + (i + 1) % HIST_DIM3D); prop.covariance += (count - mean) * (count_next - mean); } } @@ -270,212 +274,223 @@ struct test_histogram3d_functor { // // Templated test that uses the above functors. // -template +template struct test_random_scalar { typedef typename RandomGenerator::generator_type rnd_type; - int pass_mean,pass_var,pass_covar; - int pass_hist1d_mean,pass_hist1d_var,pass_hist1d_covar; - int pass_hist3d_mean,pass_hist3d_var,pass_hist3d_covar; + int pass_mean, pass_var, pass_covar; + int pass_hist1d_mean, pass_hist1d_var, pass_hist1d_covar; + int pass_hist3d_mean, pass_hist3d_var, pass_hist3d_covar; - test_random_scalar (typename test_random_functor::type_1d& density_1d, - typename test_random_functor::type_3d& density_3d, - RandomGenerator& pool, - unsigned int num_draws) - { + test_random_scalar( + typename test_random_functor::type_1d& density_1d, + typename test_random_functor::type_3d& density_3d, + RandomGenerator& pool, unsigned int num_draws) { + using Kokkos::parallel_reduce; using std::cout; using std::endl; - using Kokkos::parallel_reduce; { cout << " -- Testing randomness properties" << endl; RandomProperties result; typedef test_random_functor functor_type; - parallel_reduce (num_draws/1024, functor_type (pool, density_1d, density_3d), result); - - //printf("Result: %lf %lf %lf\n",result.mean/num_draws/3,result.variance/num_draws/3,result.covariance/num_draws/2); - double tolerance = 1.6*std::sqrt(1.0/num_draws); - double mean_expect = 0.5*Kokkos::rand::max(); - double variance_expect = 1.0/3.0*mean_expect*mean_expect; - double mean_eps = mean_expect/(result.mean/num_draws/3)-1.0; - double variance_eps = variance_expect/(result.variance/num_draws/3)-1.0; - double covariance_eps = result.covariance/num_draws/2/variance_expect; - pass_mean = ((-tolerance < mean_eps) && - ( tolerance > mean_eps)) ? 1:0; - pass_var = ((-1.5*tolerance < variance_eps) && - ( 1.5*tolerance > variance_eps)) ? 1:0; - pass_covar = ((-2.0*tolerance < covariance_eps) && - ( 2.0*tolerance > covariance_eps)) ? 1:0; - cout << "Pass: " << pass_mean - << " " << pass_var - << " " << mean_eps - << " " << variance_eps - << " " << covariance_eps - << " || " << tolerance << endl; + parallel_reduce(num_draws / 1024, + functor_type(pool, density_1d, density_3d), result); + + // printf("Result: %lf %lf + // %lf\n",result.mean/num_draws/3,result.variance/num_draws/3,result.covariance/num_draws/2); + double tolerance = 1.6 * std::sqrt(1.0 / num_draws); + double mean_expect = 0.5 * Kokkos::rand::max(); + double variance_expect = 1.0 / 3.0 * mean_expect * mean_expect; + double mean_eps = mean_expect / (result.mean / num_draws / 3) - 1.0; + double variance_eps = + variance_expect / (result.variance / num_draws / 3) - 1.0; + double covariance_eps = + result.covariance / num_draws / 2 / variance_expect; + pass_mean = ((-tolerance < mean_eps) && (tolerance > mean_eps)) ? 1 : 0; + pass_var = ((-1.5 * tolerance < variance_eps) && + (1.5 * tolerance > variance_eps)) + ? 1 + : 0; + pass_covar = ((-2.0 * tolerance < covariance_eps) && + (2.0 * tolerance > covariance_eps)) + ? 1 + : 0; + cout << "Pass: " << pass_mean << " " << pass_var << " " << mean_eps << " " + << variance_eps << " " << covariance_eps << " || " << tolerance + << endl; } { cout << " -- Testing 1-D histogram" << endl; RandomProperties result; - typedef test_histogram1d_functor functor_type; - parallel_reduce (HIST_DIM1D, functor_type (density_1d, num_draws), result); - - double tolerance = 6*std::sqrt(1.0/HIST_DIM1D); - double mean_expect = 1.0*num_draws*3/HIST_DIM1D; - double variance_expect = 1.0*num_draws*3/HIST_DIM1D*(1.0-1.0/HIST_DIM1D); - double covariance_expect = -1.0*num_draws*3/HIST_DIM1D/HIST_DIM1D; - double mean_eps = mean_expect/(result.mean/HIST_DIM1D)-1.0; - double variance_eps = variance_expect/(result.variance/HIST_DIM1D)-1.0; - double covariance_eps = (result.covariance/HIST_DIM1D - covariance_expect)/mean_expect; - pass_hist1d_mean = ((-0.0001 < mean_eps) && - ( 0.0001 > mean_eps)) ? 1:0; - pass_hist1d_var = ((-0.07 < variance_eps) && - ( 0.07 > variance_eps)) ? 1:0; - pass_hist1d_covar = ((-0.06 < covariance_eps) && - ( 0.06 > covariance_eps)) ? 1:0; - - cout << "Density 1D: " << mean_eps - << " " << variance_eps - << " " << (result.covariance/HIST_DIM1D/HIST_DIM1D) - << " || " << tolerance - << " " << result.min - << " " << result.max - << " || " << result.variance/HIST_DIM1D - << " " << 1.0*num_draws*3/HIST_DIM1D*(1.0-1.0/HIST_DIM1D) - << " || " << result.covariance/HIST_DIM1D - << " " << -1.0*num_draws*3/HIST_DIM1D/HIST_DIM1D - << endl; + typedef test_histogram1d_functor + functor_type; + parallel_reduce(HIST_DIM1D, functor_type(density_1d, num_draws), result); + + double tolerance = 6 * std::sqrt(1.0 / HIST_DIM1D); + double mean_expect = 1.0 * num_draws * 3 / HIST_DIM1D; + double variance_expect = + 1.0 * num_draws * 3 / HIST_DIM1D * (1.0 - 1.0 / HIST_DIM1D); + double covariance_expect = -1.0 * num_draws * 3 / HIST_DIM1D / HIST_DIM1D; + double mean_eps = mean_expect / (result.mean / HIST_DIM1D) - 1.0; + double variance_eps = + variance_expect / (result.variance / HIST_DIM1D) - 1.0; + double covariance_eps = + (result.covariance / HIST_DIM1D - covariance_expect) / mean_expect; + pass_hist1d_mean = ((-0.0001 < mean_eps) && (0.0001 > mean_eps)) ? 1 : 0; + pass_hist1d_var = + ((-0.07 < variance_eps) && (0.07 > variance_eps)) ? 1 : 0; + pass_hist1d_covar = + ((-0.06 < covariance_eps) && (0.06 > covariance_eps)) ? 1 : 0; + + cout << "Density 1D: " << mean_eps << " " << variance_eps << " " + << (result.covariance / HIST_DIM1D / HIST_DIM1D) << " || " + << tolerance << " " << result.min << " " << result.max << " || " + << result.variance / HIST_DIM1D << " " + << 1.0 * num_draws * 3 / HIST_DIM1D * (1.0 - 1.0 / HIST_DIM1D) + << " || " << result.covariance / HIST_DIM1D << " " + << -1.0 * num_draws * 3 / HIST_DIM1D / HIST_DIM1D << endl; } { cout << " -- Testing 3-D histogram" << endl; RandomProperties result; - typedef test_histogram3d_functor functor_type; - parallel_reduce (HIST_DIM1D, functor_type (density_3d, num_draws), result); - - double tolerance = 6*std::sqrt(1.0/HIST_DIM1D); - double mean_expect = 1.0*num_draws/HIST_DIM1D; - double variance_expect = 1.0*num_draws/HIST_DIM1D*(1.0-1.0/HIST_DIM1D); - double covariance_expect = -1.0*num_draws/HIST_DIM1D/HIST_DIM1D; - double mean_eps = mean_expect/(result.mean/HIST_DIM1D)-1.0; - double variance_eps = variance_expect/(result.variance/HIST_DIM1D)-1.0; - double covariance_eps = (result.covariance/HIST_DIM1D - covariance_expect)/mean_expect; - pass_hist3d_mean = ((-tolerance < mean_eps) && - ( tolerance > mean_eps)) ? 1:0; - pass_hist3d_var = ((-1.2*tolerance < variance_eps) && - ( 1.2*tolerance > variance_eps)) ? 1:0; - pass_hist3d_covar = ((-tolerance < covariance_eps) && - ( tolerance > covariance_eps)) ? 1:0; - - cout << "Density 3D: " << mean_eps - << " " << variance_eps - << " " << result.covariance/HIST_DIM1D/HIST_DIM1D - << " || " << tolerance - << " " << result.min - << " " << result.max << endl; + typedef test_histogram3d_functor + functor_type; + parallel_reduce(HIST_DIM1D, functor_type(density_3d, num_draws), result); + + double tolerance = 6 * std::sqrt(1.0 / HIST_DIM1D); + double mean_expect = 1.0 * num_draws / HIST_DIM1D; + double variance_expect = + 1.0 * num_draws / HIST_DIM1D * (1.0 - 1.0 / HIST_DIM1D); + double covariance_expect = -1.0 * num_draws / HIST_DIM1D / HIST_DIM1D; + double mean_eps = mean_expect / (result.mean / HIST_DIM1D) - 1.0; + double variance_eps = + variance_expect / (result.variance / HIST_DIM1D) - 1.0; + double covariance_eps = + (result.covariance / HIST_DIM1D - covariance_expect) / mean_expect; + pass_hist3d_mean = + ((-tolerance < mean_eps) && (tolerance > mean_eps)) ? 1 : 0; + pass_hist3d_var = ((-1.2 * tolerance < variance_eps) && + (1.2 * tolerance > variance_eps)) + ? 1 + : 0; + pass_hist3d_covar = + ((-tolerance < covariance_eps) && (tolerance > covariance_eps)) ? 1 + : 0; + + cout << "Density 3D: " << mean_eps << " " << variance_eps << " " + << result.covariance / HIST_DIM1D / HIST_DIM1D << " || " << tolerance + << " " << result.min << " " << result.max << endl; } } }; template -void test_random(unsigned int num_draws) -{ +void test_random(unsigned int num_draws) { using std::cout; using std::endl; - typename test_random_functor::type_1d density_1d("D1d"); - typename test_random_functor::type_3d density_3d("D3d"); + typename test_random_functor::type_1d density_1d("D1d"); + typename test_random_functor::type_3d density_3d("D3d"); - - uint64_t ticks = std::chrono::high_resolution_clock::now().time_since_epoch().count(); + uint64_t ticks = + std::chrono::high_resolution_clock::now().time_since_epoch().count(); cout << "Test Seed:" << ticks << endl; RandomGenerator pool(ticks); cout << "Test Scalar=int" << endl; - test_random_scalar test_int(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_int.pass_mean,1); - ASSERT_EQ( test_int.pass_var,1); - ASSERT_EQ( test_int.pass_covar,1); - ASSERT_EQ( test_int.pass_hist1d_mean,1); - ASSERT_EQ( test_int.pass_hist1d_var,1); - ASSERT_EQ( test_int.pass_hist1d_covar,1); - ASSERT_EQ( test_int.pass_hist3d_mean,1); - ASSERT_EQ( test_int.pass_hist3d_var,1); - ASSERT_EQ( test_int.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_int(density_1d, density_3d, + pool, num_draws); + ASSERT_EQ(test_int.pass_mean, 1); + ASSERT_EQ(test_int.pass_var, 1); + ASSERT_EQ(test_int.pass_covar, 1); + ASSERT_EQ(test_int.pass_hist1d_mean, 1); + ASSERT_EQ(test_int.pass_hist1d_var, 1); + ASSERT_EQ(test_int.pass_hist1d_covar, 1); + ASSERT_EQ(test_int.pass_hist3d_mean, 1); + ASSERT_EQ(test_int.pass_hist3d_var, 1); + ASSERT_EQ(test_int.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=unsigned int" << endl; - test_random_scalar test_uint(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_uint.pass_mean,1); - ASSERT_EQ( test_uint.pass_var,1); - ASSERT_EQ( test_uint.pass_covar,1); - ASSERT_EQ( test_uint.pass_hist1d_mean,1); - ASSERT_EQ( test_uint.pass_hist1d_var,1); - ASSERT_EQ( test_uint.pass_hist1d_covar,1); - ASSERT_EQ( test_uint.pass_hist3d_mean,1); - ASSERT_EQ( test_uint.pass_hist3d_var,1); - ASSERT_EQ( test_uint.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_uint( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_uint.pass_mean, 1); + ASSERT_EQ(test_uint.pass_var, 1); + ASSERT_EQ(test_uint.pass_covar, 1); + ASSERT_EQ(test_uint.pass_hist1d_mean, 1); + ASSERT_EQ(test_uint.pass_hist1d_var, 1); + ASSERT_EQ(test_uint.pass_hist1d_covar, 1); + ASSERT_EQ(test_uint.pass_hist3d_mean, 1); + ASSERT_EQ(test_uint.pass_hist3d_var, 1); + ASSERT_EQ(test_uint.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=int64_t" << endl; - test_random_scalar test_int64(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_int64.pass_mean,1); - ASSERT_EQ( test_int64.pass_var,1); - ASSERT_EQ( test_int64.pass_covar,1); - ASSERT_EQ( test_int64.pass_hist1d_mean,1); - ASSERT_EQ( test_int64.pass_hist1d_var,1); - ASSERT_EQ( test_int64.pass_hist1d_covar,1); - ASSERT_EQ( test_int64.pass_hist3d_mean,1); - ASSERT_EQ( test_int64.pass_hist3d_var,1); - ASSERT_EQ( test_int64.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_int64( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_int64.pass_mean, 1); + ASSERT_EQ(test_int64.pass_var, 1); + ASSERT_EQ(test_int64.pass_covar, 1); + ASSERT_EQ(test_int64.pass_hist1d_mean, 1); + ASSERT_EQ(test_int64.pass_hist1d_var, 1); + ASSERT_EQ(test_int64.pass_hist1d_covar, 1); + ASSERT_EQ(test_int64.pass_hist3d_mean, 1); + ASSERT_EQ(test_int64.pass_hist3d_var, 1); + ASSERT_EQ(test_int64.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=uint64_t" << endl; - test_random_scalar test_uint64(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_uint64.pass_mean,1); - ASSERT_EQ( test_uint64.pass_var,1); - ASSERT_EQ( test_uint64.pass_covar,1); - ASSERT_EQ( test_uint64.pass_hist1d_mean,1); - ASSERT_EQ( test_uint64.pass_hist1d_var,1); - ASSERT_EQ( test_uint64.pass_hist1d_covar,1); - ASSERT_EQ( test_uint64.pass_hist3d_mean,1); - ASSERT_EQ( test_uint64.pass_hist3d_var,1); - ASSERT_EQ( test_uint64.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_uint64( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_uint64.pass_mean, 1); + ASSERT_EQ(test_uint64.pass_var, 1); + ASSERT_EQ(test_uint64.pass_covar, 1); + ASSERT_EQ(test_uint64.pass_hist1d_mean, 1); + ASSERT_EQ(test_uint64.pass_hist1d_var, 1); + ASSERT_EQ(test_uint64.pass_hist1d_covar, 1); + ASSERT_EQ(test_uint64.pass_hist3d_mean, 1); + ASSERT_EQ(test_uint64.pass_hist3d_var, 1); + ASSERT_EQ(test_uint64.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=float" << endl; - test_random_scalar test_float(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_float.pass_mean,1); - ASSERT_EQ( test_float.pass_var,1); - ASSERT_EQ( test_float.pass_covar,1); - ASSERT_EQ( test_float.pass_hist1d_mean,1); - ASSERT_EQ( test_float.pass_hist1d_var,1); - ASSERT_EQ( test_float.pass_hist1d_covar,1); - ASSERT_EQ( test_float.pass_hist3d_mean,1); - ASSERT_EQ( test_float.pass_hist3d_var,1); - ASSERT_EQ( test_float.pass_hist3d_covar,1); - deep_copy(density_1d,0); - deep_copy(density_3d,0); + test_random_scalar test_float(density_1d, density_3d, + pool, num_draws); + ASSERT_EQ(test_float.pass_mean, 1); + ASSERT_EQ(test_float.pass_var, 1); + ASSERT_EQ(test_float.pass_covar, 1); + ASSERT_EQ(test_float.pass_hist1d_mean, 1); + ASSERT_EQ(test_float.pass_hist1d_var, 1); + ASSERT_EQ(test_float.pass_hist1d_covar, 1); + ASSERT_EQ(test_float.pass_hist3d_mean, 1); + ASSERT_EQ(test_float.pass_hist3d_var, 1); + ASSERT_EQ(test_float.pass_hist3d_covar, 1); + deep_copy(density_1d, 0); + deep_copy(density_3d, 0); cout << "Test Scalar=double" << endl; - test_random_scalar test_double(density_1d,density_3d,pool,num_draws); - ASSERT_EQ( test_double.pass_mean,1); - ASSERT_EQ( test_double.pass_var,1); - ASSERT_EQ( test_double.pass_covar,1); - ASSERT_EQ( test_double.pass_hist1d_mean,1); - ASSERT_EQ( test_double.pass_hist1d_var,1); - ASSERT_EQ( test_double.pass_hist1d_covar,1); - ASSERT_EQ( test_double.pass_hist3d_mean,1); - ASSERT_EQ( test_double.pass_hist3d_var,1); - ASSERT_EQ( test_double.pass_hist3d_covar,1); -} + test_random_scalar test_double( + density_1d, density_3d, pool, num_draws); + ASSERT_EQ(test_double.pass_mean, 1); + ASSERT_EQ(test_double.pass_var, 1); + ASSERT_EQ(test_double.pass_covar, 1); + ASSERT_EQ(test_double.pass_hist1d_mean, 1); + ASSERT_EQ(test_double.pass_hist1d_var, 1); + ASSERT_EQ(test_double.pass_hist1d_covar, 1); + ASSERT_EQ(test_double.pass_hist3d_mean, 1); + ASSERT_EQ(test_double.pass_hist3d_var, 1); + ASSERT_EQ(test_double.pass_hist3d_covar, 1); } +} // namespace Impl -} // namespace Test +} // namespace Test -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/algorithms/unit_tests/TestSerial.cpp b/lib/kokkos/algorithms/unit_tests/TestSerial.cpp index 9cf998f773..2eacdc2677 100644 --- a/lib/kokkos/algorithms/unit_tests/TestSerial.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestSerial.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,49 +53,36 @@ #include #include - //---------------------------------------------------------------------------- - namespace Test { -class serial : public ::testing::Test { -protected: - static void SetUpTestCase() - { - } - - static void TearDownTestCase () - { +#define SERIAL_RANDOM_XORSHIFT64(num_draws) \ + TEST(serial, Random_XorShift64) { \ + Impl::test_random >( \ + num_draws); \ } -}; -#define SERIAL_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( serial, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define SERIAL_RANDOM_XORSHIFT1024(num_draws) \ + TEST(serial, Random_XorShift1024) { \ + Impl::test_random >( \ + num_draws); \ } -#define SERIAL_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( serial, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ +#define SERIAL_SORT_UNSIGNED(size) \ + TEST(serial, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define SERIAL_SORT_UNSIGNED( size ) \ - TEST_F( serial, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Serial, unsigned >(size); \ - } - -SERIAL_RANDOM_XORSHIFT64( 10240000 ) -SERIAL_RANDOM_XORSHIFT1024( 10130144 ) +SERIAL_RANDOM_XORSHIFT64(10240000) +SERIAL_RANDOM_XORSHIFT1024(10130144) SERIAL_SORT_UNSIGNED(171) #undef SERIAL_RANDOM_XORSHIFT64 #undef SERIAL_RANDOM_XORSHIFT1024 #undef SERIAL_SORT_UNSIGNED -} // namespace Test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTSERIAL_PREVENT_LINK_ERROR() {} -#endif // KOKKOS_ENABLE_SERIAL - - +#endif // KOKKOS_ENABLE_SERIAL diff --git a/lib/kokkos/algorithms/unit_tests/TestSort.hpp b/lib/kokkos/algorithms/unit_tests/TestSort.hpp index 5fd7f09b50..310a93c93d 100644 --- a/lib/kokkos/algorithms/unit_tests/TestSort.hpp +++ b/lib/kokkos/algorithms/unit_tests/TestSort.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -43,235 +44,248 @@ #define KOKKOS_ALGORITHMS_UNITTESTS_TESTSORT_HPP #include -#include -#include -#include -#include +#include +#include +#include +#include namespace Test { -namespace Impl{ +namespace Impl { -template +template struct is_sorted_struct { typedef unsigned int value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; - is_sorted_struct(Kokkos::View keys_):keys(keys_) {} + is_sorted_struct(Kokkos::View keys_) : keys(keys_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, unsigned int& count) const { - if(keys(i)>keys(i+1)) count++; + void operator()(int i, unsigned int& count) const { + if (keys(i) > keys(i + 1)) count++; } }; -template +template struct sum { typedef double value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; - sum(Kokkos::View keys_):keys(keys_) {} + sum(Kokkos::View keys_) : keys(keys_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, double& count) const { - count+=keys(i); - } + void operator()(int i, double& count) const { count += keys(i); } }; -template +template struct bin3d_is_sorted_struct { typedef unsigned int value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; int max_bins; Scalar min; Scalar max; - bin3d_is_sorted_struct(Kokkos::View keys_,int max_bins_,Scalar min_,Scalar max_): - keys(keys_),max_bins(max_bins_),min(min_),max(max_) { - } + bin3d_is_sorted_struct(Kokkos::View keys_, + int max_bins_, Scalar min_, Scalar max_) + : keys(keys_), max_bins(max_bins_), min(min_), max(max_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, unsigned int& count) const { - int ix1 = int ((keys(i,0)-min)/max * max_bins); - int iy1 = int ((keys(i,1)-min)/max * max_bins); - int iz1 = int ((keys(i,2)-min)/max * max_bins); - int ix2 = int ((keys(i+1,0)-min)/max * max_bins); - int iy2 = int ((keys(i+1,1)-min)/max * max_bins); - int iz2 = int ((keys(i+1,2)-min)/max * max_bins); - - if (ix1>ix2) count++; - else if(ix1==ix2) { - if (iy1>iy2) count++; - else if ((iy1==iy2) && (iz1>iz2)) count++; + void operator()(int i, unsigned int& count) const { + int ix1 = int((keys(i, 0) - min) / max * max_bins); + int iy1 = int((keys(i, 1) - min) / max * max_bins); + int iz1 = int((keys(i, 2) - min) / max * max_bins); + int ix2 = int((keys(i + 1, 0) - min) / max * max_bins); + int iy2 = int((keys(i + 1, 1) - min) / max * max_bins); + int iz2 = int((keys(i + 1, 2) - min) / max * max_bins); + + if (ix1 > ix2) + count++; + else if (ix1 == ix2) { + if (iy1 > iy2) + count++; + else if ((iy1 == iy2) && (iz1 > iz2)) + count++; } } }; -template +template struct sum3D { typedef double value_type; typedef ExecutionSpace execution_space; - Kokkos::View keys; + Kokkos::View keys; - sum3D(Kokkos::View keys_):keys(keys_) {} + sum3D(Kokkos::View keys_) : keys(keys_) {} KOKKOS_INLINE_FUNCTION - void operator() (int i, double& count) const { - count+=keys(i,0); - count+=keys(i,1); - count+=keys(i,2); + void operator()(int i, double& count) const { + count += keys(i, 0); + count += keys(i, 1); + count += keys(i, 2); } }; -template -void test_1D_sort(unsigned int n,bool force_kokkos) { - typedef Kokkos::View KeyViewType; - KeyViewType keys("Keys",n); +template +void test_1D_sort(unsigned int n, bool force_kokkos) { + typedef Kokkos::View KeyViewType; + KeyViewType keys("Keys", n); // Test sorting array with all numbers equal - Kokkos::deep_copy(keys,KeyType(1)); - Kokkos::sort(keys,force_kokkos); + Kokkos::deep_copy(keys, KeyType(1)); + Kokkos::sort(keys, force_kokkos); Kokkos::Random_XorShift64_Pool g(1931); - Kokkos::fill_random(keys,g,Kokkos::Random_XorShift64_Pool::generator_type::MAX_URAND); + Kokkos::fill_random(keys, g, + Kokkos::Random_XorShift64_Pool< + ExecutionSpace>::generator_type::MAX_URAND); - double sum_before = 0.0; - double sum_after = 0.0; + double sum_before = 0.0; + double sum_after = 0.0; unsigned int sort_fails = 0; - Kokkos::parallel_reduce(n,sum(keys),sum_before); + Kokkos::parallel_reduce(n, sum(keys), sum_before); - Kokkos::sort(keys,force_kokkos); + Kokkos::sort(keys, force_kokkos); - Kokkos::parallel_reduce(n,sum(keys),sum_after); - Kokkos::parallel_reduce(n-1,is_sorted_struct(keys),sort_fails); + Kokkos::parallel_reduce(n, sum(keys), sum_after); + Kokkos::parallel_reduce( + n - 1, is_sorted_struct(keys), sort_fails); - double ratio = sum_before/sum_after; + double ratio = sum_before / sum_after; double epsilon = 1e-10; - unsigned int equal_sum = (ratio > (1.0-epsilon)) && (ratio < (1.0+epsilon)) ? 1 : 0; + unsigned int equal_sum = + (ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0; - ASSERT_EQ(sort_fails,0); - ASSERT_EQ(equal_sum,1); + ASSERT_EQ(sort_fails, 0); + ASSERT_EQ(equal_sum, 1); } -template +template void test_3D_sort(unsigned int n) { - typedef Kokkos::View KeyViewType; + typedef Kokkos::View KeyViewType; - KeyViewType keys("Keys",n*n*n); + KeyViewType keys("Keys", n * n * n); Kokkos::Random_XorShift64_Pool g(1931); - Kokkos::fill_random(keys,g,100.0); + Kokkos::fill_random(keys, g, 100.0); - double sum_before = 0.0; - double sum_after = 0.0; + double sum_before = 0.0; + double sum_after = 0.0; unsigned int sort_fails = 0; - Kokkos::parallel_reduce(keys.extent(0),sum3D(keys),sum_before); + Kokkos::parallel_reduce(keys.extent(0), sum3D(keys), + sum_before); int bin_1d = 1; - while( bin_1d*bin_1d*bin_1d*4< (int) keys.extent(0) ) bin_1d*=2; - int bin_max[3] = {bin_1d,bin_1d,bin_1d}; - typename KeyViewType::value_type min[3] = {0,0,0}; - typename KeyViewType::value_type max[3] = {100,100,100}; - - typedef Kokkos::BinOp3D< KeyViewType > BinOp; - BinOp bin_op(bin_max,min,max); - Kokkos::BinSort< KeyViewType , BinOp > - Sorter(keys,bin_op,false); + while (bin_1d * bin_1d * bin_1d * 4 < (int)keys.extent(0)) bin_1d *= 2; + int bin_max[3] = {bin_1d, bin_1d, bin_1d}; + typename KeyViewType::value_type min[3] = {0, 0, 0}; + typename KeyViewType::value_type max[3] = {100, 100, 100}; + + typedef Kokkos::BinOp3D BinOp; + BinOp bin_op(bin_max, min, max); + Kokkos::BinSort Sorter(keys, bin_op, false); Sorter.create_permute_vector(); - Sorter.template sort< KeyViewType >(keys); + Sorter.template sort(keys); - Kokkos::parallel_reduce(keys.extent(0),sum3D(keys),sum_after); - Kokkos::parallel_reduce(keys.extent(0)-1,bin3d_is_sorted_struct(keys,bin_1d,min[0],max[0]),sort_fails); + Kokkos::parallel_reduce(keys.extent(0), sum3D(keys), + sum_after); + Kokkos::parallel_reduce(keys.extent(0) - 1, + bin3d_is_sorted_struct( + keys, bin_1d, min[0], max[0]), + sort_fails); - double ratio = sum_before/sum_after; + double ratio = sum_before / sum_after; double epsilon = 1e-10; - unsigned int equal_sum = (ratio > (1.0-epsilon)) && (ratio < (1.0+epsilon)) ? 1 : 0; + unsigned int equal_sum = + (ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0; - if ( sort_fails ) - printf("3D Sort Sum: %f %f Fails: %u\n",sum_before,sum_after,sort_fails); + if (sort_fails) + printf("3D Sort Sum: %f %f Fails: %u\n", sum_before, sum_after, sort_fails); - ASSERT_EQ(sort_fails,0); - ASSERT_EQ(equal_sum,1); + ASSERT_EQ(sort_fails, 0); + ASSERT_EQ(equal_sum, 1); } //---------------------------------------------------------------------------- -template -void test_dynamic_view_sort(unsigned int n ) -{ - typedef Kokkos::Experimental::DynamicView KeyDynamicViewType; - typedef Kokkos::View KeyViewType; +template +void test_dynamic_view_sort(unsigned int n) { + typedef Kokkos::Experimental::DynamicView + KeyDynamicViewType; + typedef Kokkos::View KeyViewType; - const size_t upper_bound = 2 * n ; + const size_t upper_bound = 2 * n; const size_t min_chunk_size = 1024; KeyDynamicViewType keys("Keys", min_chunk_size, upper_bound); keys.resize_serial(n); - KeyViewType keys_view("KeysTmp", n ); + KeyViewType keys_view("KeysTmp", n); // Test sorting array with all numbers equal - Kokkos::deep_copy(keys_view,KeyType(1)); - Kokkos::deep_copy(keys,keys_view); - Kokkos::sort(keys, 0 /* begin */ , n /* end */ ); + Kokkos::deep_copy(keys_view, KeyType(1)); + Kokkos::deep_copy(keys, keys_view); + Kokkos::sort(keys, 0 /* begin */, n /* end */); Kokkos::Random_XorShift64_Pool g(1931); - Kokkos::fill_random(keys_view,g,Kokkos::Random_XorShift64_Pool::generator_type::MAX_URAND); + Kokkos::fill_random(keys_view, g, + Kokkos::Random_XorShift64_Pool< + ExecutionSpace>::generator_type::MAX_URAND); ExecutionSpace().fence(); - Kokkos::deep_copy(keys,keys_view); - //ExecutionSpace().fence(); + Kokkos::deep_copy(keys, keys_view); + // ExecutionSpace().fence(); - double sum_before = 0.0; - double sum_after = 0.0; + double sum_before = 0.0; + double sum_after = 0.0; unsigned int sort_fails = 0; - Kokkos::parallel_reduce(n,sum(keys_view),sum_before); + Kokkos::parallel_reduce(n, sum(keys_view), + sum_before); - Kokkos::sort(keys, 0 /* begin */ , n /* end */ ); + Kokkos::sort(keys, 0 /* begin */, n /* end */); - ExecutionSpace().fence(); // Need this fence to prevent BusError with Cuda - Kokkos::deep_copy( keys_view , keys ); - //ExecutionSpace().fence(); + ExecutionSpace().fence(); // Need this fence to prevent BusError with Cuda + Kokkos::deep_copy(keys_view, keys); + // ExecutionSpace().fence(); - Kokkos::parallel_reduce(n,sum(keys_view),sum_after); - Kokkos::parallel_reduce(n-1,is_sorted_struct(keys_view),sort_fails); + Kokkos::parallel_reduce(n, sum(keys_view), + sum_after); + Kokkos::parallel_reduce( + n - 1, is_sorted_struct(keys_view), sort_fails); - double ratio = sum_before/sum_after; + double ratio = sum_before / sum_after; double epsilon = 1e-10; - unsigned int equal_sum = (ratio > (1.0-epsilon)) && (ratio < (1.0+epsilon)) ? 1 : 0; - - if ( sort_fails != 0 || equal_sum != 1 ) { - std::cout << " N = " << n - << " ; sum_before = " << sum_before - << " ; sum_after = " << sum_after - << " ; ratio = " << ratio - << std::endl ; + unsigned int equal_sum = + (ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0; + + if (sort_fails != 0 || equal_sum != 1) { + std::cout << " N = " << n << " ; sum_before = " << sum_before + << " ; sum_after = " << sum_after << " ; ratio = " << ratio + << std::endl; } - ASSERT_EQ(sort_fails,0); - ASSERT_EQ(equal_sum,1); + ASSERT_EQ(sort_fails, 0); + ASSERT_EQ(equal_sum, 1); } //---------------------------------------------------------------------------- -template -void test_issue_1160() -{ +template +void test_issue_1160() { Kokkos::View element_("element", 10); Kokkos::View x_("x", 10); Kokkos::View v_("y", 10); auto h_element = Kokkos::create_mirror_view(element_); - auto h_x = Kokkos::create_mirror_view(x_); - auto h_v = Kokkos::create_mirror_view(v_); + auto h_x = Kokkos::create_mirror_view(x_); + auto h_v = Kokkos::create_mirror_view(v_); h_element(0) = 9; h_element(1) = 8; @@ -292,20 +306,21 @@ void test_issue_1160() Kokkos::deep_copy(v_, h_v); typedef decltype(element_) KeyViewType; - typedef Kokkos::BinOp1D< KeyViewType > BinOp; + typedef Kokkos::BinOp1D BinOp; int begin = 3; - int end = 8; - auto max = h_element(begin); - auto min = h_element(end - 1); + int end = 8; + auto max = h_element(begin); + auto min = h_element(end - 1); BinOp binner(end - begin, min, max); - Kokkos::BinSort Sorter(element_,begin,end,binner,false); + Kokkos::BinSort Sorter(element_, begin, end, binner, + false); Sorter.create_permute_vector(); - Sorter.sort(element_,begin,end); + Sorter.sort(element_, begin, end); - Sorter.sort(x_,begin,end); - Sorter.sort(v_,begin,end); + Sorter.sort(x_, begin, end); + Sorter.sort(v_, begin, end); Kokkos::deep_copy(h_element, element_); Kokkos::deep_copy(h_x, x_); @@ -330,18 +345,17 @@ void test_issue_1160() //---------------------------------------------------------------------------- -template -void test_sort(unsigned int N) -{ - test_1D_sort(N*N*N, true); - test_1D_sort(N*N*N, false); +template +void test_sort(unsigned int N) { + test_1D_sort(N * N * N, true); + test_1D_sort(N * N * N, false); #if !defined(KOKKOS_ENABLE_ROCM) - test_3D_sort(N); - test_dynamic_view_sort(N*N); + test_3D_sort(N); + test_dynamic_view_sort(N * N); #endif test_issue_1160(); } -} -} +} // namespace Impl +} // namespace Test #endif /* KOKKOS_ALGORITHMS_UNITTESTS_TESTSORT_HPP */ diff --git a/lib/kokkos/algorithms/unit_tests/TestThreads.cpp b/lib/kokkos/algorithms/unit_tests/TestThreads.cpp index 99cdb7da92..c75e6e8dfb 100644 --- a/lib/kokkos/algorithms/unit_tests/TestThreads.cpp +++ b/lib/kokkos/algorithms/unit_tests/TestThreads.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,51 +53,36 @@ #include #include - //---------------------------------------------------------------------------- - namespace Test { -class threads : public ::testing::Test { -protected: - static void SetUpTestCase() - { - std::cout << std::setprecision(5) << std::scientific; +#define THREADS_RANDOM_XORSHIFT64(num_draws) \ + TEST(threads, Random_XorShift64) { \ + Impl::test_random >( \ + num_draws); \ } - static void TearDownTestCase() - { +#define THREADS_RANDOM_XORSHIFT1024(num_draws) \ + TEST(threads, Random_XorShift1024) { \ + Impl::test_random >( \ + num_draws); \ } -}; -#define THREADS_RANDOM_XORSHIFT64( num_draws ) \ - TEST_F( threads, Random_XorShift64 ) { \ - Impl::test_random >(num_draws); \ +#define THREADS_SORT_UNSIGNED(size) \ + TEST(threads, SortUnsigned) { \ + Impl::test_sort(size); \ } -#define THREADS_RANDOM_XORSHIFT1024( num_draws ) \ - TEST_F( threads, Random_XorShift1024 ) { \ - Impl::test_random >(num_draws); \ - } - -#define THREADS_SORT_UNSIGNED( size ) \ - TEST_F( threads, SortUnsigned ) { \ - Impl::test_sort< Kokkos::Threads, double >(size); \ - } - - -THREADS_RANDOM_XORSHIFT64( 10240000 ) -THREADS_RANDOM_XORSHIFT1024( 10130144 ) +THREADS_RANDOM_XORSHIFT64(10240000) +THREADS_RANDOM_XORSHIFT1024(10130144) THREADS_SORT_UNSIGNED(171) #undef THREADS_RANDOM_XORSHIFT64 #undef THREADS_RANDOM_XORSHIFT1024 #undef THREADS_SORT_UNSIGNED -} // namespace Test +} // namespace Test #else void KOKKOS_ALGORITHMS_UNITTESTS_TESTTHREADS_PREVENT_LINK_ERROR() {} #endif - - diff --git a/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp b/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp index 8feb08332f..e245aad35f 100644 --- a/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp +++ b/lib/kokkos/algorithms/unit_tests/UnitTestMain.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,10 +46,9 @@ #include int main(int argc, char *argv[]) { - Kokkos::initialize(argc,argv); - ::testing::InitGoogleTest(&argc,argv); + Kokkos::initialize(argc, argv); + ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); Kokkos::finalize(); return result; } - diff --git a/lib/kokkos/benchmarks/atomic/main.cpp b/lib/kokkos/benchmarks/atomic/main.cpp index d86d196249..5f0977f754 100644 --- a/lib/kokkos/benchmarks/atomic/main.cpp +++ b/lib/kokkos/benchmarks/atomic/main.cpp @@ -1,124 +1,120 @@ -#include -#include -#include +#include +#include +#include -template -double test_atomic(int L, int N, int M,int K,int R,Kokkos::View offsets) { - Kokkos::View output("Output",N); +template +double test_atomic(int L, int N, int M, int K, int R, + Kokkos::View offsets) { + Kokkos::View output("Output", N); Kokkos::Impl::Timer timer; - for(int r = 0; r -double test_no_atomic(int L, int N, int M,int K,int R,Kokkos::View offsets) { - Kokkos::View output("Output",N); +template +double test_no_atomic(int L, int N, int M, int K, int R, + Kokkos::View offsets) { + Kokkos::View output("Output", N); Kokkos::Impl::Timer timer; - for(int r = 0; r\n"); - printf("Example Input GPU:\n"); - printf(" Histogram : 1000000 1000 1 1000 1 10 1\n"); - printf(" MD Force : 100000 100000 100 1000 20 10 4\n"); - printf(" Matrix Assembly : 100000 1000000 50 1000 20 10 4\n"); - Kokkos::finalize(); - return 0; - } + Kokkos::initialize(argc, argv); + { + if (argc < 8) { + printf("Arguments: L N M D K R T\n"); + printf(" L: Number of iterations to run\n"); + printf(" N: Length of array to do atomics into\n"); + printf(" M: Number of atomics per iteration to do\n"); + printf(" D: Distance from index i to do atomics into (randomly)\n"); + printf(" K: Number of FMAD per atomic\n"); + printf(" R: Number of repeats of the experiments\n"); + printf(" T: Type of atomic\n"); + printf(" 1 - int\n"); + printf(" 2 - long\n"); + printf(" 3 - float\n"); + printf(" 4 - double\n"); + printf(" 5 - complex\n"); + printf("Example Input GPU:\n"); + printf(" Histogram : 1000000 1000 1 1000 1 10 1\n"); + printf(" MD Force : 100000 100000 100 1000 20 10 4\n"); + printf(" Matrix Assembly : 100000 1000000 50 1000 20 10 4\n"); + Kokkos::finalize(); + return 0; + } + int L = atoi(argv[1]); + int N = atoi(argv[2]); + int M = atoi(argv[3]); + int D = atoi(argv[4]); + int K = atoi(argv[5]); + int R = atoi(argv[6]); + int type = atoi(argv[7]); - int L = atoi(argv[1]); - int N = atoi(argv[2]); - int M = atoi(argv[3]); - int D = atoi(argv[4]); - int K = atoi(argv[5]); - int R = atoi(argv[6]); - int type = atoi(argv[7]); - - Kokkos::View offsets("Offsets",L,M); - Kokkos::Random_XorShift64_Pool<> pool(12371); - Kokkos::fill_random(offsets,pool,D); - double time = 0; - if(type==1) - time = test_atomic(L,N,M,K,R,offsets); - if(type==2) - time = test_atomic(L,N,M,K,R,offsets); - if(type==3) - time = test_atomic(L,N,M,K,R,offsets); - if(type==4) - time = test_atomic(L,N,M,K,R,offsets); - if(type==5) - time = test_atomic >(L,N,M,K,R,offsets); + Kokkos::View offsets("Offsets", L, M); + Kokkos::Random_XorShift64_Pool<> pool(12371); + Kokkos::fill_random(offsets, pool, D); + double time = 0; + if (type == 1) time = test_atomic(L, N, M, K, R, offsets); + if (type == 2) time = test_atomic(L, N, M, K, R, offsets); + if (type == 3) time = test_atomic(L, N, M, K, R, offsets); + if (type == 4) time = test_atomic(L, N, M, K, R, offsets); + if (type == 5) + time = test_atomic >(L, N, M, K, R, offsets); - double time2 = 1; - if(type==1) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==2) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==3) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==4) - time2 = test_no_atomic(L,N,M,K,R,offsets); - if(type==5) - time2 = test_no_atomic >(L,N,M,K,R,offsets); + double time2 = 1; + if (type == 1) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 2) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 3) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 4) time2 = test_no_atomic(L, N, M, K, R, offsets); + if (type == 5) + time2 = test_no_atomic >(L, N, M, K, R, offsets); - int size = 0; - if(type==1) size = sizeof(int); - if(type==2) size = sizeof(long); - if(type==3) size = sizeof(float); - if(type==4) size = sizeof(double); - if(type==5) size = sizeof(Kokkos::complex); + int size = 0; + if (type == 1) size = sizeof(int); + if (type == 2) size = sizeof(long); + if (type == 3) size = sizeof(float); + if (type == 4) size = sizeof(double); + if (type == 5) size = sizeof(Kokkos::complex); - printf("%i\n",size); - printf("Time: %s %i %i %i %i %i %i (t_atomic: %e t_nonatomic: %e ratio: %lf )( GUpdates/s: %lf GB/s: %lf )\n", - (type==1)?"int": ( - (type==2)?"long": ( - (type==3)?"float": ( - (type==4)?"double":"complex"))), - L,N,M,D,K,R,time,time2,time/time2, - 1.e-9*L*R*M/time, 1.0*L*R*M*2*size/time/1024/1024/1024); -} + printf("%i\n", size); + printf( + "Time: %s %i %i %i %i %i %i (t_atomic: %e t_nonatomic: %e ratio: %lf " + ")( GUpdates/s: %lf GB/s: %lf )\n", + (type == 1) + ? "int" + : ((type == 2) + ? "long" + : ((type == 3) ? "float" + : ((type == 4) ? "double" : "complex"))), + L, N, M, D, K, R, time, time2, time / time2, 1.e-9 * L * R * M / time, + 1.0 * L * R * M * 2 * size / time / 1024 / 1024 / 1024); + } Kokkos::finalize(); } - diff --git a/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp b/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp index 59b4d50c44..62d7ef4a4c 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/bench.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,59 +42,52 @@ //@HEADER */ -#include -#include +#include +#include -template +template struct Run { -static void run(int N, int K, int R, int F, int T, int S); + static void run(int N, int K, int R, int F, int T, int S); }; -template +template struct RunStride { -static void run_1(int N, int K, int R, int F, int T, int S); -static void run_2(int N, int K, int R, int F, int T, int S); -static void run_3(int N, int K, int R, int F, int T, int S); -static void run_4(int N, int K, int R, int F, int T, int S); -static void run_5(int N, int K, int R, int F, int T, int S); -static void run_6(int N, int K, int R, int F, int T, int S); -static void run_7(int N, int K, int R, int F, int T, int S); -static void run_8(int N, int K, int R, int F, int T, int S); -static void run(int N, int K, int R, int U, int F, int T, int S); + static void run_1(int N, int K, int R, int F, int T, int S); + static void run_2(int N, int K, int R, int F, int T, int S); + static void run_3(int N, int K, int R, int F, int T, int S); + static void run_4(int N, int K, int R, int F, int T, int S); + static void run_5(int N, int K, int R, int F, int T, int S); + static void run_6(int N, int K, int R, int F, int T, int S); + static void run_7(int N, int K, int R, int F, int T, int S); + static void run_8(int N, int K, int R, int F, int T, int S); + static void run(int N, int K, int R, int U, int F, int T, int S); }; #define STRIDE 1 -#include +#include #undef STRIDE #define STRIDE 2 -#include +#include #undef STRIDE #define STRIDE 4 -#include +#include #undef STRIDE #define STRIDE 8 -#include +#include #undef STRIDE #define STRIDE 16 -#include +#include #undef STRIDE #define STRIDE 32 -#include +#include #undef STRIDE -template +template void run_stride_unroll(int N, int K, int R, int D, int U, int F, int T, int S) { - if(D == 1) - RunStride::run(N,K,R,U,F,T,S); - if(D == 2) - RunStride::run(N,K,R,U,F,T,S); - if(D == 4) - RunStride::run(N,K,R,U,F,T,S); - if(D == 8) - RunStride::run(N,K,R,U,F,T,S); - if(D == 16) - RunStride::run(N,K,R,U,F,T,S); - if(D == 32) - RunStride::run(N,K,R,U,F,T,S); + if (D == 1) RunStride::run(N, K, R, U, F, T, S); + if (D == 2) RunStride::run(N, K, R, U, F, T, S); + if (D == 4) RunStride::run(N, K, R, U, F, T, S); + if (D == 8) RunStride::run(N, K, R, U, F, T, S); + if (D == 16) RunStride::run(N, K, R, U, F, T, S); + if (D == 32) RunStride::run(N, K, R, U, F, T, S); } - diff --git a/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp b/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp index 6509c654e7..64817fe9dc 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/bench_stride.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,84 +42,82 @@ //@HEADER */ - #define UNROLL 1 -#include +#include #undef UNROLL #define UNROLL 2 -#include +#include #undef UNROLL #define UNROLL 3 -#include +#include #undef UNROLL #define UNROLL 4 -#include +#include #undef UNROLL #define UNROLL 5 -#include +#include #undef UNROLL #define UNROLL 6 -#include +#include #undef UNROLL #define UNROLL 7 -#include +#include #undef UNROLL #define UNROLL 8 -#include +#include #undef UNROLL -template -struct RunStride { -static void run_1(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_2(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_3(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_4(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_5(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_6(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_7(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} -static void run_8(int N, int K, int R, int F, int T, int S) { - Run::run(N,K,R,F,T,S); -} - -static void run(int N, int K, int R, int U, int F, int T, int S) { - if(U==1) { - run_1(N,K,R,F,T,S); +template +struct RunStride { + static void run_1(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==2) { - run_2(N,K,R,F,T,S); + static void run_2(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==3) { - run_3(N,K,R,F,T,S); + static void run_3(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==4) { - run_4(N,K,R,F,T,S); + static void run_4(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==5) { - run_5(N,K,R,F,T,S); + static void run_5(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==6) { - run_6(N,K,R,F,T,S); + static void run_6(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==7) { - run_7(N,K,R,F,T,S); + static void run_7(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); + } + static void run_8(int N, int K, int R, int F, int T, int S) { + Run::run(N, K, R, F, T, S); } - if(U==8) { - run_8(N,K,R,F,T,S); - } -} -}; + static void run(int N, int K, int R, int U, int F, int T, int S) { + if (U == 1) { + run_1(N, K, R, F, T, S); + } + if (U == 2) { + run_2(N, K, R, F, T, S); + } + if (U == 3) { + run_3(N, K, R, F, T, S); + } + if (U == 4) { + run_4(N, K, R, F, T, S); + } + if (U == 5) { + run_5(N, K, R, F, T, S); + } + if (U == 6) { + run_6(N, K, R, F, T, S); + } + if (U == 7) { + run_7(N, K, R, F, T, S); + } + if (U == 8) { + run_8(N, K, R, F, T, S); + } + } +}; diff --git a/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp b/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp index c6651da1e7..00ce635a48 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/bench_unroll_stride.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,108 +42,110 @@ //@HEADER */ -template -struct Run { -static void run(int N, int K, int R, int F, int T, int S) { - Kokkos::View A("A",N,K); - Kokkos::View B("B",N,K); - Kokkos::View C("C",N,K); +template +struct Run { + static void run(int N, int K, int R, int F, int T, int S) { + Kokkos::View A("A", N, K); + Kokkos::View B("B", N, K); + Kokkos::View C("C", N, K); - Kokkos::deep_copy(A,Scalar(1.5)); - Kokkos::deep_copy(B,Scalar(2.5)); - Kokkos::deep_copy(C,Scalar(3.5)); + Kokkos::deep_copy(A, Scalar(1.5)); + Kokkos::deep_copy(B, Scalar(2.5)); + Kokkos::deep_copy(C, Scalar(3.5)); - Kokkos::Timer timer; - Kokkos::parallel_for("BenchmarkKernel",Kokkos::TeamPolicy<>(N,T).set_scratch_size(0,Kokkos::PerTeam(S)), - KOKKOS_LAMBDA ( const Kokkos::TeamPolicy<>::member_type& team) { - const int n = team.league_rank(); - for(int r=0; r1) - Scalar a2 = a1*1.3; -#endif -#if(UNROLL>2) - Scalar a3 = a2*1.1; -#endif -#if(UNROLL>3) - Scalar a4 = a3*1.1; -#endif -#if(UNROLL>4) - Scalar a5 = a4*1.3; -#endif -#if(UNROLL>5) - Scalar a6 = a5*1.1; -#endif -#if(UNROLL>6) - Scalar a7 = a6*1.1; -#endif -#if(UNROLL>7) - Scalar a8 = a7*1.1; + Kokkos::Timer timer; + Kokkos::parallel_for( + "BenchmarkKernel", + Kokkos::TeamPolicy<>(N, T).set_scratch_size(0, Kokkos::PerTeam(S)), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type& team) { + const int n = team.league_rank(); + for (int r = 0; r < R; r++) { + Kokkos::parallel_for( + Kokkos::TeamThreadRange(team, 0, K), [&](const int& i) { + Scalar a1 = A(n, i, 0); + const Scalar b = B(n, i, 0); +#if (UNROLL > 1) + Scalar a2 = a1 * 1.3; +#endif +#if (UNROLL > 2) + Scalar a3 = a2 * 1.1; +#endif +#if (UNROLL > 3) + Scalar a4 = a3 * 1.1; +#endif +#if (UNROLL > 4) + Scalar a5 = a4 * 1.3; +#endif +#if (UNROLL > 5) + Scalar a6 = a5 * 1.1; +#endif +#if (UNROLL > 6) + Scalar a7 = a6 * 1.1; +#endif +#if (UNROLL > 7) + Scalar a8 = a7 * 1.1; #endif - - for(int f = 0; f1) - a2 += b*a2; + for (int f = 0; f < F; f++) { + a1 += b * a1; +#if (UNROLL > 1) + a2 += b * a2; #endif -#if(UNROLL>2) - a3 += b*a3; +#if (UNROLL > 2) + a3 += b * a3; #endif -#if(UNROLL>3) - a4 += b*a4; +#if (UNROLL > 3) + a4 += b * a4; #endif -#if(UNROLL>4) - a5 += b*a5; +#if (UNROLL > 4) + a5 += b * a5; #endif -#if(UNROLL>5) - a6 += b*a6; +#if (UNROLL > 5) + a6 += b * a6; #endif -#if(UNROLL>6) - a7 += b*a7; +#if (UNROLL > 6) + a7 += b * a7; #endif -#if(UNROLL>7) - a8 += b*a8; +#if (UNROLL > 7) + a8 += b * a8; #endif - - - } -#if(UNROLL==1) - C(n,i,0) = a1; + } +#if (UNROLL == 1) + C(n, i, 0) = a1; #endif -#if(UNROLL==2) - C(n,i,0) = a1+a2; +#if (UNROLL == 2) + C(n, i, 0) = a1 + a2; #endif -#if(UNROLL==3) - C(n,i,0) = a1+a2+a3; +#if (UNROLL == 3) + C(n, i, 0) = a1 + a2 + a3; #endif -#if(UNROLL==4) - C(n,i,0) = a1+a2+a3+a4; +#if (UNROLL == 4) + C(n, i, 0) = a1 + a2 + a3 + a4; #endif -#if(UNROLL==5) - C(n,i,0) = a1+a2+a3+a4+a5; +#if (UNROLL == 5) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5; #endif -#if(UNROLL==6) - C(n,i,0) = a1+a2+a3+a4+a5+a6; +#if (UNROLL == 6) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5 + a6; #endif -#if(UNROLL==7) - C(n,i,0) = a1+a2+a3+a4+a5+a6+a7; +#if (UNROLL == 7) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5 + a6 + a7; #endif -#if(UNROLL==8) - C(n,i,0) = a1+a2+a3+a4+a5+a6+a7+a8; +#if (UNROLL == 8) + C(n, i, 0) = a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; #endif + }); + } + }); + Kokkos::fence(); + double seconds = timer.seconds(); - }); - } - }); - Kokkos::fence(); - double seconds = timer.seconds(); - - double bytes = 1.0*N*K*R*3*sizeof(Scalar); - double flops = 1.0*N*K*R*(F*2*UNROLL + 2*(UNROLL-1)); - printf("NKRUFTS: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: %lf\n",N,K,R,UNROLL,F,T,S,seconds,1.0*bytes/seconds/1024/1024/1024,1.e-9*flops/seconds); -} + double bytes = 1.0 * N * K * R * 3 * sizeof(Scalar); + double flops = 1.0 * N * K * R * (F * 2 * UNROLL + 2 * (UNROLL - 1)); + printf( + "NKRUFTS: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: " + "%lf\n", + N, K, R, UNROLL, F, T, S, seconds, + 1.0 * bytes / seconds / 1024 / 1024 / 1024, 1.e-9 * flops / seconds); + } }; - diff --git a/lib/kokkos/benchmarks/bytes_and_flops/main.cpp b/lib/kokkos/benchmarks/bytes_and_flops/main.cpp index 4f46b38717..c21a16200e 100644 --- a/lib/kokkos/benchmarks/bytes_and_flops/main.cpp +++ b/lib/kokkos/benchmarks/bytes_and_flops/main.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,25 +42,27 @@ //@HEADER */ -#include -#include -#include -#include +#include +#include +#include +#include int main(int argc, char* argv[]) { Kokkos::initialize(); - - if(argc<10) { + if (argc < 10) { printf("Arguments: N K R D U F T S\n"); printf(" P: Precision (1==float, 2==double)\n"); printf(" N,K: dimensions of the 2D array to allocate\n"); printf(" R: how often to loop through the K dimension with each team\n"); printf(" D: distance between loaded elements (stride)\n"); printf(" U: how many independent flops to do per load\n"); - printf(" F: how many times to repeat the U unrolled operations before reading next element\n"); + printf( + " F: how many times to repeat the U unrolled operations before " + "reading next element\n"); printf(" T: team size\n"); - printf(" S: shared memory per team (used to control occupancy on GPUs)\n"); + printf( + " S: shared memory per team (used to control occupancy on GPUs)\n"); printf("Example Input GPU:\n"); printf(" Bandwidth Bound : 2 100000 1024 1 1 1 1 256 6000\n"); printf(" Cache Bound : 2 100000 1024 64 1 1 1 512 20000\n"); @@ -70,7 +73,6 @@ int main(int argc, char* argv[]) { return 0; } - int P = atoi(argv[1]); int N = atoi(argv[2]); int K = atoi(argv[3]); @@ -81,17 +83,25 @@ int main(int argc, char* argv[]) { int T = atoi(argv[8]); int S = atoi(argv[9]); - if(U>8) {printf("U must be 1-8\n"); return 0;} - if( (D!=1) && (D!=2) && (D!=4) && (D!=8) && (D!=16) && (D!=32)) {printf("D must be one of 1,2,4,8,16,32\n"); return 0;} - if( (P!=1) && (P!=2) ) {printf("P must be one of 1,2\n"); return 0;} + if (U > 8) { + printf("U must be 1-8\n"); + return 0; + } + if ((D != 1) && (D != 2) && (D != 4) && (D != 8) && (D != 16) && (D != 32)) { + printf("D must be one of 1,2,4,8,16,32\n"); + return 0; + } + if ((P != 1) && (P != 2)) { + printf("P must be one of 1,2\n"); + return 0; + } - if(P==1) { - run_stride_unroll(N,K,R,D,U,F,T,S); + if (P == 1) { + run_stride_unroll(N, K, R, D, U, F, T, S); } - if(P==2) { - run_stride_unroll(N,K,R,D,U,F,T,S); + if (P == 2) { + run_stride_unroll(N, K, R, D, U, F, T, S); } Kokkos::finalize(); } - diff --git a/lib/kokkos/benchmarks/gather/gather.hpp b/lib/kokkos/benchmarks/gather/gather.hpp index bbbd65850f..239614184b 100644 --- a/lib/kokkos/benchmarks/gather/gather.hpp +++ b/lib/kokkos/benchmarks/gather/gather.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,52 +42,44 @@ //@HEADER */ -template +template struct RunGather { static void run(int N, int K, int D, int R, int F); }; #define UNROLL 1 -#include +#include #undef UNROLL #define UNROLL 2 -#include +#include #undef UNROLL #define UNROLL 3 -#include +#include #undef UNROLL #define UNROLL 4 -#include +#include #undef UNROLL #define UNROLL 5 -#include +#include #undef UNROLL #define UNROLL 6 -#include +#include #undef UNROLL #define UNROLL 7 -#include +#include #undef UNROLL #define UNROLL 8 -#include +#include #undef UNROLL -template +template void run_gather_test(int N, int K, int D, int R, int U, int F) { - if(U == 1) - RunGather::run(N,K,D,R,F); - if(U == 2) - RunGather::run(N,K,D,R,F); - if(U == 3) - RunGather::run(N,K,D,R,F); - if(U == 4) - RunGather::run(N,K,D,R,F); - if(U == 5) - RunGather::run(N,K,D,R,F); - if(U == 6) - RunGather::run(N,K,D,R,F); - if(U == 7) - RunGather::run(N,K,D,R,F); - if(U == 8) - RunGather::run(N,K,D,R,F); + if (U == 1) RunGather::run(N, K, D, R, F); + if (U == 2) RunGather::run(N, K, D, R, F); + if (U == 3) RunGather::run(N, K, D, R, F); + if (U == 4) RunGather::run(N, K, D, R, F); + if (U == 5) RunGather::run(N, K, D, R, F); + if (U == 6) RunGather::run(N, K, D, R, F); + if (U == 7) RunGather::run(N, K, D, R, F); + if (U == 8) RunGather::run(N, K, D, R, F); } diff --git a/lib/kokkos/benchmarks/gather/gather_unroll.hpp b/lib/kokkos/benchmarks/gather/gather_unroll.hpp index 1d9c99adf9..4dc046f99c 100644 --- a/lib/kokkos/benchmarks/gather/gather_unroll.hpp +++ b/lib/kokkos/benchmarks/gather/gather_unroll.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,129 +42,132 @@ //@HEADER */ -#include -#include +#include +#include -template -struct RunGather { -static void run(int N, int K, int D, int R, int F) { - Kokkos::View connectivity("Connectivity",N,K); - Kokkos::View A_in("Input",N); - Kokkos::View B_in("Input",N); - Kokkos::View C("Output",N); +template +struct RunGather { + static void run(int N, int K, int D, int R, int F) { + Kokkos::View connectivity("Connectivity", N, K); + Kokkos::View A_in("Input", N); + Kokkos::View B_in("Input", N); + Kokkos::View C("Output", N); - Kokkos::Random_XorShift64_Pool<> rand_pool(12313); + Kokkos::Random_XorShift64_Pool<> rand_pool(12313); - Kokkos::deep_copy(A_in,1.5); - Kokkos::deep_copy(B_in,2.0); + Kokkos::deep_copy(A_in, 1.5); + Kokkos::deep_copy(B_in, 2.0); - Kokkos::View > A(A_in); - Kokkos::View > B(B_in); - - Kokkos::parallel_for("InitKernel",N, - KOKKOS_LAMBDA (const int& i) { - auto rand_gen = rand_pool.get_state(); - for( int jj=0; jj > A( + A_in); + Kokkos::View > B( + B_in); + Kokkos::parallel_for( + "InitKernel", N, KOKKOS_LAMBDA(const int& i) { + auto rand_gen = rand_pool.get_state(); + for (int jj = 0; jj < K; jj++) { + connectivity(i, jj) = (rand_gen.rand(D) + i - D / 2 + N) % N; + } + rand_pool.free_state(rand_gen); + }); + Kokkos::fence(); - Kokkos::Timer timer; - for(int r = 0; r1) - Scalar a2 = a1*Scalar(1.3); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::parallel_for( + "BenchmarkKernel", N, KOKKOS_LAMBDA(const int& i) { + Scalar c = Scalar(0.0); + for (int jj = 0; jj < K; jj++) { + const int j = connectivity(i, jj); + Scalar a1 = A(j); + const Scalar b = B(j); +#if (UNROLL > 1) + Scalar a2 = a1 * Scalar(1.3); #endif -#if(UNROLL>2) - Scalar a3 = a2*Scalar(1.1); +#if (UNROLL > 2) + Scalar a3 = a2 * Scalar(1.1); #endif -#if(UNROLL>3) - Scalar a4 = a3*Scalar(1.1); +#if (UNROLL > 3) + Scalar a4 = a3 * Scalar(1.1); #endif -#if(UNROLL>4) - Scalar a5 = a4*Scalar(1.3); +#if (UNROLL > 4) + Scalar a5 = a4 * Scalar(1.3); #endif -#if(UNROLL>5) - Scalar a6 = a5*Scalar(1.1); +#if (UNROLL > 5) + Scalar a6 = a5 * Scalar(1.1); #endif -#if(UNROLL>6) - Scalar a7 = a6*Scalar(1.1); +#if (UNROLL > 6) + Scalar a7 = a6 * Scalar(1.1); #endif -#if(UNROLL>7) - Scalar a8 = a7*Scalar(1.1); +#if (UNROLL > 7) + Scalar a8 = a7 * Scalar(1.1); #endif - - for(int f = 0; f1) - a2 += b*a2; + for (int f = 0; f < F; f++) { + a1 += b * a1; +#if (UNROLL > 1) + a2 += b * a2; #endif -#if(UNROLL>2) - a3 += b*a3; +#if (UNROLL > 2) + a3 += b * a3; #endif -#if(UNROLL>3) - a4 += b*a4; +#if (UNROLL > 3) + a4 += b * a4; #endif -#if(UNROLL>4) - a5 += b*a5; +#if (UNROLL > 4) + a5 += b * a5; #endif -#if(UNROLL>5) - a6 += b*a6; +#if (UNROLL > 5) + a6 += b * a6; #endif -#if(UNROLL>6) - a7 += b*a7; +#if (UNROLL > 6) + a7 += b * a7; #endif -#if(UNROLL>7) - a8 += b*a8; +#if (UNROLL > 7) + a8 += b * a8; #endif - - - } -#if(UNROLL==1) - c += a1; + } +#if (UNROLL == 1) + c += a1; #endif -#if(UNROLL==2) - c += a1+a2; +#if (UNROLL == 2) + c += a1 + a2; #endif -#if(UNROLL==3) - c += a1+a2+a3; +#if (UNROLL == 3) + c += a1 + a2 + a3; #endif -#if(UNROLL==4) - c += a1+a2+a3+a4; +#if (UNROLL == 4) + c += a1 + a2 + a3 + a4; #endif -#if(UNROLL==5) - c += a1+a2+a3+a4+a5; +#if (UNROLL == 5) + c += a1 + a2 + a3 + a4 + a5; #endif -#if(UNROLL==6) - c += a1+a2+a3+a4+a5+a6; +#if (UNROLL == 6) + c += a1 + a2 + a3 + a4 + a5 + a6; #endif -#if(UNROLL==7) - c += a1+a2+a3+a4+a5+a6+a7; +#if (UNROLL == 7) + c += a1 + a2 + a3 + a4 + a5 + a6 + a7; #endif -#if(UNROLL==8) - c += a1+a2+a3+a4+a5+a6+a7+a8; +#if (UNROLL == 8) + c += a1 + a2 + a3 + a4 + a5 + a6 + a7 + a8; #endif + } + C(i) = c; + }); + Kokkos::fence(); + } + double seconds = timer.seconds(); - } - C(i) = c ; - }); - Kokkos::fence(); + double bytes = 1.0 * N * K * R * (2 * sizeof(Scalar) + sizeof(int)) + + 1.0 * N * R * sizeof(Scalar); + double flops = 1.0 * N * K * R * (F * 2 * UNROLL + 2 * (UNROLL - 1)); + double gather_ops = 1.0 * N * K * R * 2; + printf( + "SNKDRUF: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: " + "%lf GGather/s: %lf\n", + sizeof(Scalar) / 4, N, K, D, R, UNROLL, F, seconds, + 1.0 * bytes / seconds / 1024 / 1024 / 1024, 1.e-9 * flops / seconds, + 1.e-9 * gather_ops / seconds); } - double seconds = timer.seconds(); - - double bytes = 1.0*N*K*R*(2*sizeof(Scalar)+sizeof(int)) + 1.0*N*R*sizeof(Scalar); - double flops = 1.0*N*K*R*(F*2*UNROLL + 2*(UNROLL-1)); - double gather_ops = 1.0*N*K*R*2; - printf("SNKDRUF: %i %i %i %i %i %i %i Time: %lfs Bandwidth: %lfGiB/s GFlop/s: %lf GGather/s: %lf\n",sizeof(Scalar)/4,N,K,D,R,UNROLL,F,seconds,1.0*bytes/seconds/1024/1024/1024,1.e-9*flops/seconds,1.e-9*gather_ops/seconds); -} }; diff --git a/lib/kokkos/benchmarks/gather/main.cpp b/lib/kokkos/benchmarks/gather/main.cpp index ca5238e7fd..6a2db3e024 100644 --- a/lib/kokkos/benchmarks/gather/main.cpp +++ b/lib/kokkos/benchmarks/gather/main.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,23 +42,26 @@ //@HEADER */ -#include -#include -#include -#include +#include +#include +#include +#include int main(int argc, char* argv[]) { - Kokkos::initialize(argc,argv); + Kokkos::initialize(argc, argv); - if(argc<8) { + if (argc < 8) { printf("Arguments: S N K D\n"); - printf(" S: Scalar Type Size (1==float, 2==double, 4=complex)\n"); + printf( + " S: Scalar Type Size (1==float, 2==double, 4=complex)\n"); printf(" N: Number of entities\n"); printf(" K: Number of things to gather per entity\n"); printf(" D: Max distance of gathered things of an entity\n"); printf(" R: how often to loop through the K dimension with each team\n"); printf(" U: how many independent flops to do per load\n"); - printf(" F: how many times to repeat the U unrolled operations before reading next element\n"); + printf( + " F: how many times to repeat the U unrolled operations before " + "reading next element\n"); printf("Example Input GPU:\n"); printf(" Bandwidth Bound : 2 10000000 1 1 10 1 1\n"); printf(" Cache Bound : 2 10000000 64 1 10 1 1\n"); @@ -68,7 +72,6 @@ int main(int argc, char* argv[]) { return 0; } - int S = atoi(argv[1]); int N = atoi(argv[2]); int K = atoi(argv[3]); @@ -77,17 +80,22 @@ int main(int argc, char* argv[]) { int U = atoi(argv[6]); int F = atoi(argv[7]); - if( (S!=1) && (S!=2) && (S!=4)) {printf("S must be one of 1,2,4\n"); return 0;} - if( N(N,K,D,R,U,F); + if ((S != 1) && (S != 2) && (S != 4)) { + printf("S must be one of 1,2,4\n"); + return 0; + } + if (N < D) { + printf("N must be larger or equal to D\n"); + return 0; + } + if (S == 1) { + run_gather_test(N, K, D, R, U, F); } - if(S==2) { - run_gather_test(N,K,D,R,U,F); + if (S == 2) { + run_gather_test(N, K, D, R, U, F); } - if(S==4) { - run_gather_test >(N,K,D,R,U,F); + if (S == 4) { + run_gather_test >(N, K, D, R, U, F); } Kokkos::finalize(); } - diff --git a/lib/kokkos/benchmarks/gups/gups-kokkos.cc b/lib/kokkos/benchmarks/gups/gups-kokkos.cc index 4602adda79..9ac59be4a6 100644 --- a/lib/kokkos/benchmarks/gups/gups-kokkos.cc +++ b/lib/kokkos/benchmarks/gups/gups-kokkos.cc @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/benchmarks/policy_performance/main.cpp b/lib/kokkos/benchmarks/policy_performance/main.cpp index 2f5395734a..332e5574da 100644 --- a/lib/kokkos/benchmarks/policy_performance/main.cpp +++ b/lib/kokkos/benchmarks/policy_performance/main.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,67 +45,86 @@ #include #include "policy_perf_test.hpp" -int main(int argc, char* argv[] ) { - Kokkos::initialize(argc,argv); +int main(int argc, char* argv[]) { + Kokkos::initialize(argc, argv); - if(argc<10) { + if (argc < 10) { printf(" Ten arguments are needed to run this program:\n"); - printf(" (1)team_range, (2)thread_range, (3)vector_range, (4)outer_repeat, (5)thread_repeat, (6)vector_repeat, (7)team_size, (8)vector_size, (9)schedule, (10)test_type\n"); + printf( + " (1)team_range, (2)thread_range, (3)vector_range, (4)outer_repeat, " + "(5)thread_repeat, (6)vector_repeat, (7)team_size, (8)vector_size, " + "(9)schedule, (10)test_type\n"); printf(" team_range: number of teams (league_size)\n"); printf(" thread_range: range for nested TeamThreadRange parallel_*\n"); printf(" vector_range: range for nested ThreadVectorRange parallel_*\n"); printf(" outer_repeat: number of repeats for outer parallel_* call\n"); - printf(" thread_repeat: number of repeats for TeamThreadRange parallel_* call\n"); - printf(" vector_repeat: number of repeats for ThreadVectorRange parallel_* call\n"); + printf( + " thread_repeat: number of repeats for TeamThreadRange parallel_* " + "call\n"); + printf( + " vector_repeat: number of repeats for ThreadVectorRange parallel_* " + "call\n"); printf(" team_size: number of team members (team_size)\n"); printf(" vector_size: desired vectorization (if possible)\n"); printf(" schedule: 1 == Static 2 == Dynamic\n"); - printf(" test_type: 3-digit code XYZ for testing (nested) parallel_*\n"); - printf(" code key: XYZ X in {1,2,3,4,5}, Y in {0,1,2}, Z in {0,1,2}\n"); + printf( + " test_type: 3-digit code XYZ for testing (nested) parallel_*\n"); + printf( + " code key: XYZ X in {1,2,3,4,5}, Y in {0,1,2}, Z in " + "{0,1,2}\n"); printf(" TeamPolicy:\n"); - printf(" X: 0 = none (never used, makes no sense); 1 = parallel_for; 2 = parallel_reduce\n"); - printf(" Y: 0 = none; 1 = parallel_for; 2 = parallel_reduce\n"); - printf(" Z: 0 = none; 1 = parallel_for; 2 = parallel_reduce\n"); + printf( + " X: 0 = none (never used, makes no sense); 1 = " + "parallel_for; 2 = parallel_reduce\n"); + printf( + " Y: 0 = none; 1 = parallel_for; 2 = " + "parallel_reduce\n"); + printf( + " Z: 0 = none; 1 = parallel_for; 2 = " + "parallel_reduce\n"); printf(" RangePolicy:\n"); - printf(" X: 3 = parallel_for; 4 = parallel_reduce; 5 = parallel_scan\n"); + printf( + " X: 3 = parallel_for; 4 = parallel_reduce; 5 = " + "parallel_scan\n"); printf(" Y: 0 = none\n"); printf(" Z: 0 = none\n"); printf(" Example Input:\n"); - printf(" 100000 32 32 100 100 100 8 1 1 100\n"); + printf(" 100000 32 32 100 100 100 8 1 1 100\n"); Kokkos::finalize(); return 0; } - int team_range = atoi(argv[1]); + int team_range = atoi(argv[1]); int thread_range = atoi(argv[2]); int vector_range = atoi(argv[3]); - int outer_repeat = atoi(argv[4]); + int outer_repeat = atoi(argv[4]); int thread_repeat = atoi(argv[5]); int vector_repeat = atoi(argv[6]); - int team_size = atoi(argv[7]); + int team_size = atoi(argv[7]); int vector_size = atoi(argv[8]); - int schedule = atoi(argv[9]); - int test_type = atoi(argv[10]); + int schedule = atoi(argv[9]); + int test_type = atoi(argv[10]); - int disable_verbose_output = 0; - if ( argc > 11 ) { + int disable_verbose_output = 0; + if (argc > 11) { disable_verbose_output = atoi(argv[11]); } - if ( schedule != 1 && schedule != 2 ) { + if (schedule != 1 && schedule != 2) { printf("schedule: %d\n", schedule); printf("Options for schedule are: 1 == Static 2 == Dynamic\n"); Kokkos::finalize(); return -1; } - if ( test_type != 100 && test_type != 110 && test_type != 111 && test_type != 112 && test_type != 120 && test_type != 121 && test_type != 122 - && test_type != 200 && test_type != 210 && test_type != 211 && test_type != 212 && test_type != 220 && test_type != 221 && test_type != 222 - && test_type != 300 && test_type != 400 && test_type != 500 - ) - { + if (test_type != 100 && test_type != 110 && test_type != 111 && + test_type != 112 && test_type != 120 && test_type != 121 && + test_type != 122 && test_type != 200 && test_type != 210 && + test_type != 211 && test_type != 212 && test_type != 220 && + test_type != 221 && test_type != 222 && test_type != 300 && + test_type != 400 && test_type != 500) { printf("Incorrect test_type option\n"); Kokkos::finalize(); return -2; @@ -112,56 +132,85 @@ int main(int argc, char* argv[] ) { double result = 0.0; - Kokkos::parallel_reduce( "parallel_reduce warmup", Kokkos::TeamPolicy<>(10,1), - KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type team, double& lval) { - lval += 1; - }, result); + Kokkos::parallel_reduce( + "parallel_reduce warmup", Kokkos::TeamPolicy<>(10, 1), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type team, + double& lval) { lval += 1; }, + result); - typedef Kokkos::View view_type_1d; - typedef Kokkos::View view_type_2d; + typedef Kokkos::View view_type_1d; + typedef Kokkos::View view_type_2d; typedef Kokkos::View view_type_3d; // Allocate view without initializing - // Call a 'warmup' test with 1 repeat - this will initialize the corresponding view appropriately for test and should obey first-touch etc - // Second call to test is the one we actually care about and time - view_type_1d v_1( Kokkos::ViewAllocateWithoutInitializing("v_1"), team_range*team_size); - view_type_2d v_2( Kokkos::ViewAllocateWithoutInitializing("v_2"), team_range*team_size, thread_range); - view_type_3d v_3( Kokkos::ViewAllocateWithoutInitializing("v_3"), team_range*team_size, thread_range, vector_range); + // Call a 'warmup' test with 1 repeat - this will initialize the corresponding + // view appropriately for test and should obey first-touch etc Second call to + // test is the one we actually care about and time + view_type_1d v_1(Kokkos::ViewAllocateWithoutInitializing("v_1"), + team_range * team_size); + view_type_2d v_2(Kokkos::ViewAllocateWithoutInitializing("v_2"), + team_range * team_size, thread_range); + view_type_3d v_3(Kokkos::ViewAllocateWithoutInitializing("v_3"), + team_range * team_size, thread_range, vector_range); double result_computed = 0.0; - double result_expect = 0.0; - double time = 0.0; + double result_expect = 0.0; + double time = 0.0; - if(schedule==1) { - if ( test_type != 500 ) { + if (schedule == 1) { + if (test_type != 500) { // warmup - no repeat of loops - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - } - else { + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, test_type, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); + } else { // parallel_scan: initialize 1d view for parallel_scan - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,100,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, 100, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); } } - if(schedule==2) { - if ( test_type != 500 ) { + if (schedule == 2) { + if (test_type != 500) { // warmup - no repeat of loops - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); - } - else { + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, test_type, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); + } else { // parallel_scan: initialize 1d view for parallel_scan - test_policy,int>(team_range,thread_range,vector_range,1,1,1,team_size,vector_size,100,v_1,v_2,v_3,result_computed,result_expect,time); - test_policy,int>(team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,test_type,v_1,v_2,v_3,result_computed,result_expect,time); + test_policy, int>( + team_range, thread_range, vector_range, 1, 1, 1, team_size, + vector_size, 100, v_1, v_2, v_3, result_computed, result_expect, + time); + test_policy, int>( + team_range, thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, test_type, v_1, v_2, v_3, + result_computed, result_expect, time); } } - if ( disable_verbose_output == 0 ) { - printf("%7i %4i %2i %9i %4i %4i %4i %2i %1i %3i %e %e %lf\n",team_range,thread_range,vector_range,outer_repeat,thread_repeat,vector_repeat,team_size,vector_size,schedule,test_type,result_computed,result_expect,time); - } - else { - printf("%lf\n",time); + if (disable_verbose_output == 0) { + printf("%7i %4i %2i %9i %4i %4i %4i %2i %1i %3i %e %e %lf\n", team_range, + thread_range, vector_range, outer_repeat, thread_repeat, + vector_repeat, team_size, vector_size, schedule, test_type, + result_computed, result_expect, time); + } else { + printf("%lf\n", time); } Kokkos::finalize(); diff --git a/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp b/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp index 1ab437928d..7a1500891f 100644 --- a/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp +++ b/lib/kokkos/benchmarks/policy_performance/policy_perf_test.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -43,297 +44,375 @@ #include -template < class ViewType > +template struct ParallelScanFunctor { using value_type = double; ViewType v; - ParallelScanFunctor( const ViewType & v_ ) - : v(v_) - {} + ParallelScanFunctor(const ViewType& v_) : v(v_) {} KOKKOS_INLINE_FUNCTION - void operator()( const int idx, value_type& val, const bool& final ) const - { - // inclusive scan - val += v(idx); - if ( final ) { - v(idx) = val; - } + void operator()(const int idx, value_type& val, const bool& final) const { + // inclusive scan + val += v(idx); + if (final) { + v(idx) = val; } + } }; -template +template void test_policy(int team_range, int thread_range, int vector_range, - int outer_repeat, int thread_repeat, int inner_repeat, - int team_size, int vector_size, int test_type, - ViewType1 &v1, ViewType2 &v2, ViewType3 &v3, - double &result, double &result_expect, double &time) { - - typedef Kokkos::TeamPolicy t_policy; + int outer_repeat, int thread_repeat, int inner_repeat, + int team_size, int vector_size, int test_type, ViewType1& v1, + ViewType2& v2, ViewType3& v3, double& result, + double& result_expect, double& time) { + typedef Kokkos::TeamPolicy t_policy; typedef typename t_policy::member_type t_team; Kokkos::Timer timer; - for(int orep = 0; orep(v1) + Kokkos::parallel_scan("500 outer scan", team_size * team_range, + ParallelScanFunctor(v1) #if 0 // This does not compile with pre Cuda 8.0 - see Github Issue #913 for explanation KOKKOS_LAMBDA (const int idx, double& val, const bool& final) { @@ -345,11 +424,12 @@ void test_policy(int team_range, int thread_range, int vector_range, } #endif ); - // result = v1( team_size*team_range - 1 ); // won't work with Cuda - need to copy result back to host to print - // result_expect = 0.5*(team_size*team_range)*(team_size*team_range-1); + // result = v1( team_size*team_range - 1 ); // won't work with Cuda - need + // to copy result back to host to print result_expect = + // 0.5*(team_size*team_range)*(team_size*team_range-1); } - } // end outer for loop + } // end outer for loop time = timer.seconds(); -} //end test_policy +} // end test_policy diff --git a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh index 1c2db56648..f4bfb87f8f 100755 --- a/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh +++ b/lib/kokkos/benchmarks/policy_performance/script_sample_usage.sh @@ -2,7 +2,7 @@ # Sample script for benchmarking policy performance -# Suggested environment variables to export prior to executing script: +# Suggested enviroment variables to export prior to executing script: # KNL: # OMP_NUM_THREADS=256 KMP_AFFINITY=compact # Power: diff --git a/lib/kokkos/benchmarks/stream/stream-kokkos.cc b/lib/kokkos/benchmarks/stream/stream-kokkos.cc index 370995432e..6ce789dd82 100644 --- a/lib/kokkos/benchmarks/stream/stream-kokkos.cc +++ b/lib/kokkos/benchmarks/stream/stream-kokkos.cc @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR diff --git a/lib/kokkos/bin/hpcbind b/lib/kokkos/bin/hpcbind index 6af091a7d8..b185a92821 100755 --- a/lib/kokkos/bin/hpcbind +++ b/lib/kokkos/bin/hpcbind @@ -383,7 +383,7 @@ fi # Check unknown arguments ################################################################################ if [[ ${#UNKNOWN_ARGS[*]} > 0 ]]; then - echo "HPCBIND Unknown options: ${UNKNOWN_ARGS[*]}" > >(tee -a ${HPCBIND_LOG}) + echo "HPCBIND Uknown options: ${UNKNOWN_ARGS[*]}" > >(tee -a ${HPCBIND_LOG}) exit 1 fi diff --git a/lib/kokkos/bin/nvcc_wrapper b/lib/kokkos/bin/nvcc_wrapper index 94bc72854e..8a23d0d620 100755 --- a/lib/kokkos/bin/nvcc_wrapper +++ b/lib/kokkos/bin/nvcc_wrapper @@ -85,11 +85,11 @@ first_xcompiler_arg=1 temp_dir=${TMPDIR:-/tmp} -# Check if we have an optimization argument already -optimization_applied=0 +# optimization flag added as a command-line argument +optimization_flag="" -# Check if we have -std=c++X or --std=c++X already -stdcxx_applied=0 +# std standard flag added as a command-line argument +std_flag="" # Run nvcc a second time to generate dependencies if needed depfile_separate=0 @@ -99,6 +99,10 @@ depfile_target_arg="" # Option to remove duplicate libraries and object files remove_duplicate_link_files=0 +function warn_std_flag() { + echo "nvcc_wrapper - *warning* you have set multiple standard flags (-std=c++1* or --std=c++1*), only the last is used because nvcc can only accept a single std setting" +} + #echo "Arguments: $# $@" while [ $# -gt 0 ] @@ -130,12 +134,16 @@ do ;; # Ensure we only have one optimization flag because NVCC doesn't allow muliple -O*) - if [ $optimization_applied -eq 1 ]; then - echo "nvcc_wrapper - *warning* you have set multiple optimization flags (-O*), only the first is used because nvcc can only accept a single optimization setting." + if [ -n "$optimization_flag" ]; then + echo "nvcc_wrapper - *warning* you have set multiple optimization flags (-O*), only the last is used because nvcc can only accept a single optimization setting." + shared_args=${shared_args/ $optimization_flag/} + fi + if [ "$1" = "-O" ]; then + optimization_flag="-O2" else - shared_args="$shared_args $1" - optimization_applied=1 + optimization_flag=$1 fi + shared_args="$shared_args $optimization_flag" ;; #Handle shared args (valid for both nvcc and the host compiler) -D*) @@ -171,7 +179,7 @@ do shift ;; #Handle known nvcc args - --dryrun|--verbose|--keep|--keep-dir*|-G|--relocatable-device-code*|-lineinfo|-expt-extended-lambda|--resource-usage|-Xptxas*) + --dryrun|--verbose|--keep|--keep-dir*|-G|--relocatable-device-code*|-lineinfo|-expt-extended-lambda|--resource-usage|-Xptxas*|--fmad*) cuda_args="$cuda_args $1" ;; #Handle more known nvcc args @@ -179,21 +187,43 @@ do cuda_args="$cuda_args $1" ;; #Handle known nvcc args that have an argument - -rdc|-maxrregcount|--default-stream) + -rdc|-maxrregcount|--default-stream|-Xnvlink|--fmad) cuda_args="$cuda_args $1 $2" shift ;; -rdc=*|-maxrregcount*|--maxrregcount*) cuda_args="$cuda_args $1" ;; - #Handle c++11 - --std=c++11|-std=c++11|--std=c++14|-std=c++14|--std=c++1y|-std=c++1y|--std=c++17|-std=c++17|--std=c++1z|-std=c++1z) - if [ $stdcxx_applied -eq 1 ]; then - echo "nvcc_wrapper - *warning* you have set multiple optimization flags (-std=c++1* or --std=c++1*), only the first is used because nvcc can only accept a single std setting" - else - shared_args="$shared_args $1" - stdcxx_applied=1 + #Handle unsupported standard flags + --std=c++1y|-std=c++1y|--std=c++1z|-std=c++1z|--std=gnu++1y|-std=gnu++1y|--std=gnu++1z|-std=gnu++1z|--std=c++2a|-std=c++2a|--std=c++17|-std=c++17) + fallback_std_flag="-std=c++14" + # this is hopefully just occurring in a downstream project during CMake feature tests + # we really have no choice here but to accept the flag and change to an accepted C++ standard + echo "nvcc_wrapper does not accept standard flags $1 since partial standard flags and standards after C++14 are not supported. nvcc_wrapper will use $fallback_std_flag instead. It is undefined behavior to use this flag. This should only be occurring during CMake configuration." + if [ -n "$std_flag" ]; then + warn_std_flag + shared_args=${shared_args/ $std_flag/} + fi + std_flag=$fallback_std_flag + shared_args="$shared_args $std_flag" + ;; + -std=gnu*) + corrected_std_flag=${1/gnu/c} + echo "nvcc_wrapper has been given GNU extension standard flag $1 - reverting flag to $corrected_std_flag" + if [ -n "$std_flag" ]; then + warn_std_flag + shared_args=${shared_args/ $std_flag/} + fi + std_flag=$corrected_std_flag + shared_args="$shared_args $std_flag" + ;; + --std=c++11|-std=c++11|--std=c++14|-std=c++14) + if [ -n "$std_flag" ]; then + warn_std_flag + shared_args=${shared_args/ $std_flag/} fi + std_flag=$1 + shared_args="$shared_args $std_flag" ;; #strip of -std=c++98 due to nvcc warnings and Tribits will place both -std=c++11 and -std=c++98 @@ -308,16 +338,6 @@ do shift done -#Check if nvcc exists -if [ $host_only -ne 1 ]; then - var=$(which nvcc ) - if [ $? -gt 0 ]; then - echo "Could not find nvcc in PATH" - exit $? - fi -fi - - # Only print host compiler version if [ $get_host_version -eq 1 ]; then $host_compiler --version @@ -372,6 +392,9 @@ if [ $first_xcompiler_arg -eq 0 ]; then nvcc_command="$nvcc_command -Xcompiler $xcompiler_args" fi +#Replace all commas in xcompiler_args with a space for the host only command +xcompiler_args=${xcompiler_args//,/" "} + #Compose host only command host_command="$host_compiler $shared_args $host_only_args $compile_arg $output_arg $xcompiler_args $host_linker_args $shared_versioned_libraries_host" diff --git a/lib/kokkos/cm_generate_makefile.bash b/lib/kokkos/cm_generate_makefile.bash new file mode 100755 index 0000000000..fd7cfe2d32 --- /dev/null +++ b/lib/kokkos/cm_generate_makefile.bash @@ -0,0 +1,339 @@ +#!/bin/bash + +update_kokkos_devices() { + SEARCH_TEXT="*$1*" + if [[ $KOKKOS_DEVICES == $SEARCH_TEXT ]]; then + echo kokkos devices already includes $SEARCH_TEXT + else + if [ "$KOKKOS_DEVICES" = "" ]; then + KOKKOS_DEVICES="$1" + echo reseting kokkos devices to $KOKKOS_DEVICES + else + KOKKOS_DEVICES="${KOKKOS_DEVICES},$1" + echo appending to kokkos devices $KOKKOS_DEVICES + fi + fi +} + +get_kokkos_device_list() { + KOKKOS_DEVICE_CMD= + PARSE_DEVICES_LST=$(echo $KOKKOS_DEVICES | tr "," "\n") + for DEVICE_ in $PARSE_DEVICES_LST + do + UC_DEVICE=$(echo $DEVICE_ | tr "[:lower:]" "[:upper:]") + KOKKOS_DEVICE_CMD="-DKokkos_ENABLE_${UC_DEVICE}=ON ${KOKKOS_DEVICE_CMD}" + done +} + +get_kokkos_arch_list() { + KOKKOS_ARCH_CMD= + PARSE_ARCH_LST=$(echo $KOKKOS_ARCH | tr "," "\n") + for ARCH_ in $PARSE_ARCH_LST + do + UC_ARCH=$(echo $ARCH_ | tr "[:lower:]" "[:upper:]") + KOKKOS_ARCH_CMD="-DKokkos_ARCH_${UC_ARCH}=ON ${KOKKOS_ARCH_CMD}" + done +} + +get_kokkos_cuda_option_list() { + echo parsing KOKKOS_CUDA_OPTIONS=$KOKKOS_CUDA_OPTIONS + KOKKOS_CUDA_OPTION_CMD= + PARSE_CUDA_LST=$(echo $KOKKOS_CUDA_OPTIONS | tr "," "\n") + for CUDA_ in $PARSE_CUDA_LST + do + CUDA_OPT_NAME= + if [ "${CUDA_}" == "enable_lambda" ]; then + CUDA_OPT_NAME=CUDA_LAMBDA + elif [ "${CUDA_}" == "rdc" ]; then + CUDA_OPT_NAME=CUDA_RELOCATABLE_DEVICE_CODE + elif [ "${CUDA_}" == "force_uvm" ]; then + CUDA_OPT_NAME=CUDA_UVM + elif [ "${CUDA_}" == "use_ldg" ]; then + CUDA_OPT_NAME=CUDA_LDG_INTRINSIC + else + echo "${CUDA_} is not a valid cuda options..." + fi + if [ "${CUDA_OPT_NAME}" != "" ]; then + KOKKOS_CUDA_OPTION_CMD="-DKokkos_ENABLE_${CUDA_OPT_NAME}=ON ${KOKKOS_CUDA_OPTION_CMD}" + fi + done +} + +get_kokkos_option_list() { + echo parsing KOKKOS_OPTIONS=$KOKKOS_OPTIONS + KOKKOS_OPTION_CMD= + PARSE_OPTIONS_LST=$(echo $KOKKOS_OPTIONS | tr "," "\n") + for OPT_ in $PARSE_OPTIONS_LST + do + UC_OPT_=$(echo $OPT_ | tr "[:lower:]" "[:upper:]") + if [[ "$UC_OPT_" == *DISABLE* ]]; then + FLIP_OPT_=${UC_OPT_/DISABLE/ENABLE} + KOKKOS_OPTION_CMD="-DKokkos_${FLIP_OPT_}=OFF ${KOKKOS_OPTION_CMD}" + elif [[ "$UC_OPT_" == *ENABLE* ]]; then + KOKKOS_OPTION_CMD="-DKokkos_${UC_OPT_}=ON ${KOKKOS_OPTION_CMD}" + else + KOKKOS_OPTION_CMD="-DKokkos_ENABLE_${UC_OPT_}=ON ${KOKKOS_OPTION_CMD}" + fi + done +} + +display_help_text() { + + echo "Kokkos configure options:" + echo "" + echo "--kokkos-path=/Path/To/Kokkos: Path to the Kokkos root directory." + echo "--prefix=/Install/Path: Path to install the Kokkos library." + echo "" + echo "--with-cuda[=/Path/To/Cuda]: Enable Cuda and set path to Cuda Toolkit." + echo "--with-openmp: Enable OpenMP backend." + echo "--with-pthread: Enable Pthreads backend." + echo "--with-serial: Enable Serial backend." + echo "--with-devices: Explicitly add a set of backends." + echo "" + echo "--arch=[OPT]: Set target architectures. Options are:" + echo " [AMD]" + echo " AMDAVX = AMD CPU" + echo " EPYC = AMD EPYC Zen-Core CPU" + echo " [ARM]" + echo " ARMv80 = ARMv8.0 Compatible CPU" + echo " ARMv81 = ARMv8.1 Compatible CPU" + echo " ARMv8-ThunderX = ARMv8 Cavium ThunderX CPU" + echo " ARMv8-TX2 = ARMv8 Cavium ThunderX2 CPU" + echo " [IBM]" + echo " BGQ = IBM Blue Gene Q" + echo " Power7 = IBM POWER7 and POWER7+ CPUs" + echo " Power8 = IBM POWER8 CPUs" + echo " Power9 = IBM POWER9 CPUs" + echo " [Intel]" + echo " WSM = Intel Westmere CPUs" + echo " SNB = Intel Sandy/Ivy Bridge CPUs" + echo " HSW = Intel Haswell CPUs" + echo " BDW = Intel Broadwell Xeon E-class CPUs" + echo " SKX = Intel Sky Lake Xeon E-class HPC CPUs (AVX512)" + echo " [Intel Xeon Phi]" + echo " KNC = Intel Knights Corner Xeon Phi" + echo " KNL = Intel Knights Landing Xeon Phi" + echo " [NVIDIA]" + echo " Kepler30 = NVIDIA Kepler generation CC 3.0" + echo " Kepler32 = NVIDIA Kepler generation CC 3.2" + echo " Kepler35 = NVIDIA Kepler generation CC 3.5" + echo " Kepler37 = NVIDIA Kepler generation CC 3.7" + echo " Maxwell50 = NVIDIA Maxwell generation CC 5.0" + echo " Maxwell52 = NVIDIA Maxwell generation CC 5.2" + echo " Maxwell53 = NVIDIA Maxwell generation CC 5.3" + echo " Pascal60 = NVIDIA Pascal generation CC 6.0" + echo " Pascal61 = NVIDIA Pascal generation CC 6.1" + echo " Volta70 = NVIDIA Volta generation CC 7.0" + echo " Volta72 = NVIDIA Volta generation CC 7.2" + echo "" + echo "--compiler=/Path/To/Compiler Set the compiler." + echo "--debug,-dbg: Enable Debugging." + echo "--cxxflags=[FLAGS] Overwrite CXXFLAGS for library build and test" + echo " build. This will still set certain required" + echo " flags via KOKKOS_CXXFLAGS (such as -fopenmp," + echo " --std=c++11, etc.)." + echo "--cxxstandard=[FLAGS] Overwrite KOKKOS_CXX_STANDARD for library build and test" + echo " c++11 (default), c++14, c++17, c++1y, c++1z, c++2a" + echo "--ldflags=[FLAGS] Overwrite LDFLAGS for library build and test" + echo " build. This will still set certain required" + echo " flags via KOKKOS_LDFLAGS (such as -fopenmp," + echo " -lpthread, etc.)." + echo "--with-gtest=/Path/To/Gtest: Set path to gtest. (Used in unit and performance" + echo " tests.)" + echo "--with-hwloc=/Path/To/Hwloc: Set path to hwloc library." + echo "--with-memkind=/Path/To/MemKind: Set path to memkind library." + echo "--with-options=[OPT]: Additional options to Kokkos:" + echo " compiler_warnings" + echo " aggressive_vectorization = add ivdep on loops" + echo " disable_profiling = do not compile with profiling hooks" + echo " " + echo "--with-cuda-options=[OPT]: Additional options to CUDA:" + echo " force_uvm, use_ldg, enable_lambda, rdc" + echo "--with-hpx-options=[OPT]: Additional options to HPX:" + echo " enable_async_dispatch" + echo "--gcc-toolchain=/Path/To/GccRoot: Set the gcc toolchain to use with clang (e.g. /usr)" + echo "--make-j=[NUM]: DEPRECATED: call make with appropriate" + echo " -j flag" + +} + +while [[ $# > 0 ]] +do + key="$1" + + case $key in + --kokkos-path*) + KOKKOS_PATH="${key#*=}" + ;; + --hpx-path*) + HPX_PATH="${key#*=}" + ;; + --prefix*) + PREFIX="${key#*=}" + ;; + --with-cuda) + update_kokkos_devices Cuda + CUDA_PATH_NVCC=$(command -v nvcc) + CUDA_PATH=${CUDA_PATH_NVCC%/bin/nvcc} + ;; + # Catch this before '--with-cuda*' + --with-cuda-options*) + KOKKOS_CUDA_OPTIONS="${key#*=}" + ;; + --with-cuda*) + update_kokkos_devices Cuda + CUDA_PATH="${key#*=}" + ;; + --with-openmp) + update_kokkos_devices OpenMP + ;; + --with-pthread) + update_kokkos_devices Pthread + ;; + --with-serial) + update_kokkos_devices Serial + ;; + --with-hpx-options*) + KOKKOS_HPX_OPT="${key#*=}" + ;; + --with-hpx*) + update_kokkos_devices HPX + if [ -z "$HPX_PATH" ]; then + HPX_PATH="${key#*=}" + fi + ;; + --with-devices*) + DEVICES="${key#*=}" + PARSE_DEVICES=$(echo $DEVICES | tr "," "\n") + for DEVICE_ in $PARSE_DEVICES + do + update_kokkos_devices $DEVICE_ + done + ;; + --with-gtest*) + GTEST_PATH="${key#*=}" + ;; + --with-hwloc*) + HWLOC_PATH="${key#*=}" + ;; + --with-memkind*) + MEMKIND_PATH="${key#*=}" + ;; + --arch*) + KOKKOS_ARCH="${key#*=}" + ;; + --cxxflags*) + KOKKOS_CXXFLAGS="${key#*=}" + KOKKOS_CXXFLAGS=${KOKKOS_CXXFLAGS//,/ } + ;; + --cxxstandard*) + KOKKOS_CXX_STANDARD="${key#*=}" + ;; + --ldflags*) + KOKKOS_LDFLAGS="${key#*=}" + ;; + --debug|-dbg) + KOKKOS_DEBUG=yes + ;; + --make-j*) + echo "Warning: ${key} is deprecated" + echo "Call make with appropriate -j flag" + ;; + --compiler*) + COMPILER="${key#*=}" + CNUM=$(command -v ${COMPILER} 2>&1 >/dev/null | grep "no ${COMPILER}" | wc -l) + if [ ${CNUM} -gt 0 ]; then + echo "Invalid compiler by --compiler command: '${COMPILER}'" + exit + fi + if [[ ! -n ${COMPILER} ]]; then + echo "Empty compiler specified by --compiler command." + exit + fi + CNUM=$(command -v ${COMPILER} | grep ${COMPILER} | wc -l) + if [ ${CNUM} -eq 0 ]; then + echo "Invalid compiler by --compiler command: '${COMPILER}'" + exit + fi + # ... valid compiler, ensure absolute path set + WCOMPATH=$(command -v $COMPILER) + COMPDIR=$(dirname $WCOMPATH) + COMPNAME=$(basename $WCOMPATH) + COMPILER=${COMPDIR}/${COMPNAME} + ;; + --with-options*) + KOKKOS_OPTIONS="${key#*=}" + ;; + --gcc-toolchain*) + KOKKOS_GCC_TOOLCHAIN="${key#*=}" + ;; + --help) + display_help_text + exit 0 + ;; + *) + echo "warning: ignoring unknown option $key" + ;; + esac + + shift +done + + +if [ "$COMPILER" == "" ]; then + COMPILER_CMD= +else + COMPILER_CMD=-DCMAKE_CXX_COMPILER=$COMPILER +fi + +if [ "$KOKKOS_DEBUG" == "" ]; then + KOKKOS_DEBUG_CMD=-DCMAKE_BUILD_TYPE=RELEASE +else + KOKKOS_DEBUG_CMD=-DCMAKE_BUILD_TYPE=DEBUG +fi + +if [ ! -e ${KOKKOS_PATH}/CMakeLists.txt ]; then + if [ "${KOKKOS_PATH}" == "" ]; then + CM_SCRIPT=$0 + KOKKOS_PATH=`dirname $CM_SCRIPT` + if [ ! -e ${KOKKOS_PATH}/CMakeLists.txt ]; then + echo "${KOKKOS_PATH} repository appears to not be complete. please verify and try again" + exit 0 + fi + else + echo "KOKKOS_PATH does not appear to be set properly. please specify in location of CMakeLists.txt" + display_help_text + exit 0 + fi +fi + +get_kokkos_device_list +get_kokkos_option_list +get_kokkos_arch_list +get_kokkos_cuda_option_list + +## if HPX is enabled, we need to enforce cxx standard = 14 +if [[ ${KOKKOS_DEVICE_CMD} == *Kokkos_ENABLE_HPX* ]]; then + if [ "${KOKKOS_CXX_STANDARD}" == "" ] || [ ${#KOKKOS_CXX_STANDARD} -lt 14 ]; then + echo CXX Standard must be 14 or higher for HPX to work. + KOKKOS_CXX_STANDARD=14 + fi +fi + +if [ "$KOKKOS_CXX_STANDARD" == "" ]; then + STANDARD_CMD= +else + STANDARD_CMD=-DKokkos_CXX_STANDARD=${KOKKOS_CXX_STANDARD} +fi + +if [[ ${COMPILER} == *clang* ]]; then + gcc_path=$(which g++ | awk --field-separator='/bin/g++' '{printf $1}' ) + KOKKOS_CXXFLAGS="${KOKKOS_CXXFLAGS} --gcc-toolchain=${gcc_path}" + + if [ ! "${CUDA_PATH}" == "" ]; then + KOKKOS_CXXFLAGS="${KOKKOS_CXXFLAGS} --cuda-path=${CUDA_PATH}" + fi +fi + +echo cmake $COMPILER_CMD -DCMAKE_CXX_FLAGS="${KOKKOS_CXXFLAGS}" -DCMAKE_EXE_LINKER_FLAGS="${KOKKOS_LDFLAGS}" -DCMAKE_INSTALL_PREFIX=${PREFIX} ${KOKKOS_DEVICE_CMD} ${KOKKOS_ARCH_CMD} -DKokkos_ENABLE_TESTS=ON ${KOKKOS_OPTION_CMD} ${KOKKOS_CUDA_OPTION_CMD} -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_EXTENSIONS=OFF ${STANDARD_CMD} ${KOKKOS_DEBUG_CMD} ${KOKKOS_PATH} +cmake $COMPILER_CMD -DCMAKE_CXX_FLAGS="${KOKKOS_CXXFLAGS//\"}" -DCMAKE_EXE_LINKER_FLAGS="${KOKKOS_LDFLAGS//\"}" -DCMAKE_INSTALL_PREFIX=${PREFIX} ${KOKKOS_DEVICE_CMD} ${KOKKOS_ARCH_CMD} -DKokkos_ENABLE_TESTS=ON ${KOKKOS_OPTION_CMD} ${KOKKOS_CUDA_OPTION_CMD} -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_CXX_EXTENSIONS=OFF ${STANDARD_CMD} ${KOKKOS_DEBUG_CMD} ${KOKKOS_PATH} diff --git a/lib/kokkos/cmake/KokkosConfig.cmake.in b/lib/kokkos/cmake/KokkosConfig.cmake.in index fc099a494c..6f4607687e 100644 --- a/lib/kokkos/cmake/KokkosConfig.cmake.in +++ b/lib/kokkos/cmake/KokkosConfig.cmake.in @@ -1,18 +1,14 @@ -# - Config file for the Kokkos package -# It defines the following variables -# Kokkos_INCLUDE_DIRS - include directories for Kokkos -# Kokkos_LIBRARIES - libraries to link against - # Compute paths -GET_FILENAME_COMPONENT(Kokkos_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) -SET(Kokkos_INCLUDE_DIRS "@CONF_INCLUDE_DIRS@") +@PACKAGE_INIT@ -# Our library dependencies (contains definitions for IMPORTED targets) -IF(NOT TARGET kokkos AND NOT Kokkos_BINARY_DIR) - INCLUDE("${Kokkos_CMAKE_DIR}/KokkosTargets.cmake") -ENDIF() +#Find dependencies +INCLUDE(CMakeFindDependencyMacro) -# These are IMPORTED targets created by KokkosTargets.cmake -SET(Kokkos_LIBRARY_DIRS @INSTALL_LIB_DIR@) -SET(Kokkos_LIBRARIES @Kokkos_LIBRARIES_NAMES@) -SET(Kokkos_TPL_LIBRARIES @KOKKOS_LIBS@) +#This needs to go above the KokkosTargets in case +#the Kokkos targets depend in some way on the TPL imports +@KOKKOS_TPL_EXPORTS@ + +GET_FILENAME_COMPONENT(Kokkos_CMAKE_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH) +INCLUDE("${Kokkos_CMAKE_DIR}/KokkosTargets.cmake") +INCLUDE("${Kokkos_CMAKE_DIR}/KokkosConfigCommon.cmake") +UNSET(Kokkos_CMAKE_DIR) diff --git a/lib/kokkos/cmake/KokkosConfigCommon.cmake.in b/lib/kokkos/cmake/KokkosConfigCommon.cmake.in new file mode 100644 index 0000000000..da9c61976c --- /dev/null +++ b/lib/kokkos/cmake/KokkosConfigCommon.cmake.in @@ -0,0 +1,87 @@ +SET(Kokkos_DEVICES @KOKKOS_ENABLED_DEVICES@) +SET(Kokkos_OPTIONS @KOKKOS_ENABLED_OPTIONS@) +SET(Kokkos_TPLS @KOKKOS_ENABLED_TPLS@) +SET(Kokkos_ARCH @KOKKOS_ENABLED_ARCH_LIST@) + +# These are needed by KokkosKernels +FOREACH(DEV ${Kokkos_DEVICES}) + SET(Kokkos_ENABLE_${DEV} ON) +ENDFOREACH() + +IF(NOT Kokkos_FIND_QUIETLY) + MESSAGE(STATUS "Enabled Kokkos devices: ${Kokkos_DEVICES}") +ENDIF() + +IF (Kokkos_ENABLE_CUDA AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14.0") + #If we are building CUDA, we have tricked CMake because we declare a CXX project + #If the default C++ standard for a given compiler matches the requested + #standard, then CMake just omits the -std flag in later versions of CMake + #This breaks CUDA compilation (CUDA compiler can have a different default + #-std then the underlying host compiler by itself). Setting this variable + #forces CMake to always add the -std flag even if it thinks it doesn't need it + SET(CMAKE_CXX_STANDARD_DEFAULT 98 CACHE INTERNAL "" FORCE) +ENDIF() + +SET(KOKKOS_USE_CXX_EXTENSIONS @KOKKOS_USE_CXX_EXTENSIONS@) +IF (NOT DEFINED CMAKE_CXX_EXTENSIONS OR CMAKE_CXX_EXTENSIONS) + IF (NOT KOKKOS_USE_CXX_EXTENSIONS) + MESSAGE(WARNING "The installed Kokkos configuration does not support CXX extensions. Forcing -DCMAKE_CXX_EXTENSIONS=Off") + SET(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "" FORCE) + ENDIF() +ENDIF() + +include(FindPackageHandleStandardArgs) + +# This function makes sure that Kokkos was built with the requested backends +# and target architectures and generates a fatal error if it was not. +# +# kokkos_check( +# [DEVICES ...] # Set of backends (e.g. "OpenMP" and/or "Cuda") +# [ARCH ...] # Target architectures (e.g. "Power9" and/or "Volta70") +# [OPTIONS ...] # Optional settings (e.g. "PROFILING") +# [TPLS ...] # Third party libraries +# [RETURN_VALUE ] # Set a variable that indicates the result of the +# # check instead of a fatal error +# ) +function(kokkos_check) + set(ALLOWED_ARGS DEVICES ARCH OPTIONS TPLS) + cmake_parse_arguments(KOKKOS_CHECK "" "RETURN_VALUE" "${ALLOWED_ARGS}" ${ARGN}) + foreach(_arg ${KOKKOS_CHECK_UNPARSED_ARGUMENTS}) + message(SEND_ERROR "Argument '${_arg}' passed to kokkos_check() was not recognized") + endforeach() + # Get the list of keywords that were actually passed to the function. + set(REQUESTED_ARGS) + foreach(arg ${ALLOWED_ARGS}) + if(KOKKOS_CHECK_${arg}) + list(APPEND REQUESTED_ARGS ${arg}) + endif() + endforeach() + set(KOKKOS_CHECK_SUCCESS TRUE) + foreach(arg ${REQUESTED_ARGS}) + # Define variables named after the required arguments that are provided by + # the Kokkos install. + foreach(requested ${KOKKOS_CHECK_${arg}}) + foreach(provided ${Kokkos_${arg}}) + STRING(TOUPPER ${requested} REQUESTED_UC) + STRING(TOUPPER ${provided} PROVIDED_UC) + if(PROVIDED_UC STREQUAL REQUESTED_UC) + string(REPLACE ";" " " ${requested} "${KOKKOS_CHECK_${arg}}") + endif() + endforeach() + endforeach() + # Somewhat divert the CMake function below from its original purpose and + # use it to check that there are variables defined for all required + # arguments. Success or failure messages will be displayed but we are + # responsible for signaling failure and skip the build system generation. + find_package_handle_standard_args("Kokkos_${arg}" DEFAULT_MSG + ${KOKKOS_CHECK_${arg}}) + if(NOT Kokkos_${arg}_FOUND) + set(KOKKOS_CHECK_SUCCESS FALSE) + endif() + endforeach() + if(NOT KOKKOS_CHECK_SUCCESS AND NOT KOKKOS_CHECK_RETURN_VALUE) + message(FATAL_ERROR "Kokkos does NOT provide all backends and/or architectures requested") + else() + set(${KOKKOS_CHECK_RETURN_VALUE} ${KOKKOS_CHECK_SUCCESS} PARENT_SCOPE) + endif() +endfunction() diff --git a/lib/kokkos/cmake/KokkosCore_config.h.in b/lib/kokkos/cmake/KokkosCore_config.h.in new file mode 100644 index 0000000000..084afba8a8 --- /dev/null +++ b/lib/kokkos/cmake/KokkosCore_config.h.in @@ -0,0 +1,89 @@ + +#if !defined(KOKKOS_MACROS_HPP) || defined(KOKKOS_CORE_CONFIG_H) +#error "Do not include KokkosCore_config.h directly; include Kokkos_Macros.hpp instead." +#else +#define KOKKOS_CORE_CONFIG_H +#endif + +/* Execution Spaces */ +#cmakedefine KOKKOS_ENABLE_SERIAL +#cmakedefine KOKKOS_ENABLE_OPENMP +#cmakedefine KOKKOS_ENABLE_THREADS +#cmakedefine KOKKOS_ENABLE_CUDA +#cmakedefine KOKKOS_ENABLE_HPX +#cmakedefine KOKKOS_ENABLE_MEMKIND +#cmakedefine KOKKOS_ENABLE_LIBRT + +#ifndef __CUDA_ARCH__ +#cmakedefine KOKKOS_ENABLE_TM +#cmakedefine KOKKOS_USE_ISA_X86_64 +#cmakedefine KOKKOS_USE_ISA_KNC +#cmakedefine KOKKOS_USE_ISA_POWERPCLE +#cmakedefine KOKKOS_USE_ISA_POWERPCBE +#endif + +/* General Settings */ +#cmakedefine KOKKOS_ENABLE_CXX11 +#cmakedefine KOKKOS_ENABLE_CXX14 +#cmakedefine KOKKOS_ENABLE_CXX17 +#cmakedefine KOKKOS_ENABLE_CXX20 + +#cmakedefine KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE +#cmakedefine KOKKOS_ENABLE_CUDA_UVM +#cmakedefine KOKKOS_ENABLE_CUDA_LAMBDA +#cmakedefine KOKKOS_ENABLE_CUDA_CONSTEXPR +#cmakedefine KOKKOS_ENABLE_CUDA_LDG_INTRINSIC +#cmakedefine KOKKOS_ENABLE_HPX_ASYNC_DISPATCH +#cmakedefine KOKKOS_ENABLE_DEBUG +#cmakedefine KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK +#cmakedefine KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK +#cmakedefine KOKKOS_ENABLE_COMPILER_WARNINGS +#cmakedefine KOKKOS_ENABLE_PROFILING +#cmakedefine KOKKOS_ENABLE_PROFILING_LOAD_PRINT +#cmakedefine KOKKOS_ENABLE_DEPRECATED_CODE +#cmakedefine KOKKOS_ENABLE_ETI +#cmakedefine KOKKOS_ENABLE_LARGE_MEM_TESTS +#cmakedefine KOKKOS_ENABLE_DUALVIEW_MODIFY_CHECK +#cmakedefine KOKKOS_ENABLE_COMPLEX_ALIGN +#cmakedefine KOKKOS_OPT_RANGE_AGGRESSIVE_VECTORIZATION + +/* TPL Settings */ +#cmakedefine KOKKOS_ENABLE_HWLOC +#cmakedefine KOKKOS_USE_LIBRT +#cmakedefine KOKKOS_ENABLE_HWBSPACE + +#cmakedefine KOKKOS_IMPL_CUDA_CLANG_WORKAROUND + +#cmakedefine KOKKOS_COMPILER_CUDA_VERSION @KOKKOS_COMPILER_CUDA_VERSION@ + +#cmakedefine KOKKOS_ARCH_SSE42 +#cmakedefine KOKKOS_ARCH_ARMV80 +#cmakedefine KOKKOS_ARCH_ARMV8_THUNDERX +#cmakedefine KOKKOS_ARCH_ARMV81 +#cmakedefine KOKKOS_ARCH_ARMV8_THUNDERX2 +#cmakedefine KOKKOS_ARCH_AMD_AVX2 +#cmakedefine KOKKOS_ARCH_AVX +#cmakedefine KOKKOS_ARCH_AVX2 +#cmakedefine KOKKOS_ARCH_AVX512XEON +#cmakedefine KOKKOS_ARCH_KNC +#cmakedefine KOKKOS_ARCH_AVX512MIC +#cmakedefine KOKKOS_ARCH_POWER7 +#cmakedefine KOKKOS_ARCH_POWER8 +#cmakedefine KOKKOS_ARCH_POWER9 +#cmakedefine KOKKOS_ARCH_KEPLER +#cmakedefine KOKKOS_ARCH_KEPLER30 +#cmakedefine KOKKOS_ARCH_KEPLER32 +#cmakedefine KOKKOS_ARCH_KEPLER35 +#cmakedefine KOKKOS_ARCH_KEPLER37 +#cmakedefine KOKKOS_ARCH_MAXWELL +#cmakedefine KOKKOS_ARCH_MAXWELL50 +#cmakedefine KOKKOS_ARCH_MAXWELL52 +#cmakedefine KOKKOS_ARCH_MAXWELL53 +#cmakedefine KOKKOS_ARCH_PASCAL +#cmakedefine KOKKOS_ARCH_PASCAL60 +#cmakedefine KOKKOS_ARCH_PASCAL61 +#cmakedefine KOKKOS_ARCH_VOLTA +#cmakedefine KOKKOS_ARCH_VOLTA70 +#cmakedefine KOKKOS_ARCH_VOLTA72 +#cmakedefine KOKKOS_ARCH_TURING75 +#cmakedefine KOKKOS_ARCH_AMD_EPYC diff --git a/lib/kokkos/cmake/Makefile.generate_cmake_settings b/lib/kokkos/cmake/Makefile.generate_cmake_settings deleted file mode 100644 index da076b23db..0000000000 --- a/lib/kokkos/cmake/Makefile.generate_cmake_settings +++ /dev/null @@ -1,8 +0,0 @@ -ifndef KOKKOS_PATH - MAKEFILE_PATH := $(abspath $(lastword $(MAKEFILE_LIST))) - KOKKOS_PATH = $(subst Makefile,,$(MAKEFILE_PATH)).. -endif - -include $(KOKKOS_PATH)/Makefile.kokkos -include $(KOKKOS_PATH)/core/src/Makefile.generate_header_lists -include $(KOKKOS_PATH)/core/src/Makefile.generate_build_files diff --git a/lib/kokkos/cmake/Modules/FindHWLOC.cmake b/lib/kokkos/cmake/Modules/FindHWLOC.cmake deleted file mode 100644 index 60df8084d8..0000000000 --- a/lib/kokkos/cmake/Modules/FindHWLOC.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#.rst: -# FindHWLOC -# ---------- -# -# Try to find HWLOC, based on KOKKOS_HWLOC_DIR -# -# The following variables are defined: -# -# HWLOC_FOUND - System has HWLOC -# HWLOC_INCLUDE_DIR - HWLOC include directory -# HWLOC_LIBRARIES - Libraries needed to use HWLOC - -find_path(HWLOC_INCLUDE_DIR hwloc.h PATHS "${KOKKOS_HWLOC_DIR}/include") -find_library(HWLOC_LIBRARIES hwloc PATHS "${KOKKOS_HWLOC_DIR}/lib") - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(HWLOC DEFAULT_MSG - HWLOC_INCLUDE_DIR HWLOC_LIBRARIES) - -mark_as_advanced(HWLOC_INCLUDE_DIR HWLOC_LIBRARIES) diff --git a/lib/kokkos/cmake/Modules/FindMemkind.cmake b/lib/kokkos/cmake/Modules/FindMemkind.cmake deleted file mode 100644 index 245fb44c19..0000000000 --- a/lib/kokkos/cmake/Modules/FindMemkind.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#.rst: -# FindMemkind -# ---------- -# -# Try to find Memkind. -# -# The following variables are defined: -# -# MEMKIND_FOUND - System has Memkind -# MEMKIND_INCLUDE_DIR - Memkind include directory -# MEMKIND_LIBRARIES - Libraries needed to use Memkind - -find_path(MEMKIND_INCLUDE_DIR memkind.h) -find_library(MEMKIND_LIBRARIES memkind) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Memkind DEFAULT_MSG - MEMKIND_INCLUDE_DIR MEMKIND_LIBRARIES) - -mark_as_advanced(MEMKIND_INCLUDE_DIR MEMKIND_LIBRARIES) diff --git a/lib/kokkos/cmake/Modules/FindQthreads.cmake b/lib/kokkos/cmake/Modules/FindQthreads.cmake deleted file mode 100644 index a254b0e996..0000000000 --- a/lib/kokkos/cmake/Modules/FindQthreads.cmake +++ /dev/null @@ -1,20 +0,0 @@ -#.rst: -# FindQthreads -# ---------- -# -# Try to find Qthreads. -# -# The following variables are defined: -# -# QTHREADS_FOUND - System has Qthreads -# QTHREADS_INCLUDE_DIR - Qthreads include directory -# QTHREADS_LIBRARIES - Libraries needed to use Qthreads - -find_path(QTHREADS_INCLUDE_DIR qthread.h) -find_library(QTHREADS_LIBRARIES qthread) - -include(FindPackageHandleStandardArgs) -find_package_handle_standard_args(Qthreads DEFAULT_MSG - QTHREADS_INCLUDE_DIR QTHREADS_LIBRARIES) - -mark_as_advanced(QTHREADS_INCLUDE_DIR QTHREADS_LIBRARIES) diff --git a/lib/kokkos/cmake/Modules/FindTPLCUDA.cmake b/lib/kokkos/cmake/Modules/FindTPLCUDA.cmake new file mode 100644 index 0000000000..36aefcdb44 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLCUDA.cmake @@ -0,0 +1,13 @@ + +IF (KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + KOKKOS_FIND_IMPORTED(CUDA INTERFACE + LIBRARIES cudart cuda + LIBRARY_PATHS ENV LD_LIBRARY_PATH ENV CUDA_PATH + ALLOW_SYSTEM_PATH_FALLBACK + ) +ELSE() + KOKKOS_CREATE_IMPORTED_TPL(CUDA INTERFACE + LINK_LIBRARIES cuda + ) +ENDIF() + diff --git a/lib/kokkos/cmake/Modules/FindTPLHPX.cmake b/lib/kokkos/cmake/Modules/FindTPLHPX.cmake new file mode 100644 index 0000000000..c8b3bc4c9b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLHPX.cmake @@ -0,0 +1,15 @@ + +FIND_PACKAGE(HPX REQUIRED) +#as of right now, HPX doesn't export correctly +#so let's convert it to an interface target +KOKKOS_CREATE_IMPORTED_TPL(HPX INTERFACE + LINK_LIBRARIES ${HPX_LIBRARIES} + INCLUDES ${HPX_INCLUDE_DIRS} +) +#this is a bit funky since this is a CMake target +#but HPX doesn't export itself correctly +KOKKOS_EXPORT_CMAKE_TPL(HPX) + +#I would prefer all of this gets replaced with +#KOKKOS_IMPORT_CMAKE_TPL(HPX) + diff --git a/lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake b/lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake new file mode 100644 index 0000000000..cf763b7e5b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLHWLOC.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(HWLOC HEADER hwloc.h LIBRARY hwloc) diff --git a/lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake b/lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake new file mode 100644 index 0000000000..5fc6a69303 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLLIBDL.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(LIBDL HEADER dlfcn.h LIBRARY dl) diff --git a/lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake b/lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake new file mode 100644 index 0000000000..811db5851b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLLIBNUMA.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(LIBNUMA HEADER numa.h LIBRARY numa) diff --git a/lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake b/lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake new file mode 100644 index 0000000000..e75da56b5b --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLLIBRT.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(LIBRT HEADER time.h LIBRARY rt) diff --git a/lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake b/lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake new file mode 100644 index 0000000000..20aaff2295 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLMEMKIND.cmake @@ -0,0 +1 @@ +KOKKOS_FIND_IMPORTED(MEMKIND HEADER memkind.h LIBRARY memkind) diff --git a/lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake b/lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake new file mode 100644 index 0000000000..b4b8c34122 --- /dev/null +++ b/lib/kokkos/cmake/Modules/FindTPLPTHREAD.cmake @@ -0,0 +1,17 @@ + +TRY_COMPILE(KOKKOS_HAS_PTHREAD_ARG + ${KOKKOS_TOP_BUILD_DIR}/tpl_tests + ${KOKKOS_SOURCE_DIR}/cmake/compile_tests/pthread.cpp + LINK_LIBRARIES -pthread + COMPILE_DEFINITIONS -pthread) + +INCLUDE(FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS(PTHREAD DEFAULT_MSG KOKKOS_HAS_PTHREAD_ARG) + +KOKKOS_CREATE_IMPORTED_TPL(PTHREAD + INTERFACE #this is not a real library with a real location + COMPILE_OPTIONS -pthread + LINK_OPTIONS -pthread) + + + diff --git a/lib/kokkos/cmake/README.md b/lib/kokkos/cmake/README.md new file mode 100644 index 0000000000..2ac8731586 --- /dev/null +++ b/lib/kokkos/cmake/README.md @@ -0,0 +1,331 @@ +![Kokkos](https://avatars2.githubusercontent.com/u/10199860?s=200&v=4) + +# Developing Kokkos + +This document contains a build system overview for developers with information on adding new CMake options that could influence +* Header configuration macros +* Optional features +* Third-partly libraries +* Compiler and linker flags +For build system details for users, refer to the [build instructions](../BUILD.md). + +## Build System + +Kokkos uses CMake to configure, build, and install. +Rather than being a completely straightforward use of modern CMake, +Kokkos has several extra complications, primarily due to: +* Kokkos must support linking to an installed version or in-tree builds as a subdirectory of a larger project. +* Kokkos must configure a special compiler `nvcc_wrapper` that allows `nvcc` to accept all C++ flags (which `nvcc` currently does not). +* Kokkos must work as a part of TriBITS, a CMake library providing a particular build idiom for Trilinos. +* Kokkos has many pre-existing users. We need to be careful about breaking previous versions or generating meaningful error messags if we do break backwards compatibility. + +If you are looking at the build system code wondering why certain decisions were made: we have had to balance many competing requirements and certain technical debt. Everything in the build system was done for a reason, trying to adhere as closely as possible to modern CMake best practices while meeting all pre-existing. customer requirements. + +### Modern CMake Philosophy + +Modern CMake relies on understanding the principle of *building* and *using* a code project. +What preprocessor, compiler, and linker flags do I need to *build* my project? +What flags does a downstream project that links to me need to *use* my project? +In CMake terms, flags that are only needed for building are `PRIVATE`. +Only Kokkos needs these flags, not a package that depends on Kokkos. +Flags that must be used in a downstream project are `PUBLIC`. +Kokkos must tell other projects to use them. + +In Kokkos, almost everything is a public flag since Kokkos is driven by headers and Kokkos is in charge of optimizing your code to achieve performance portability! +Include paths, C++ standard flags, architecture-specific optimizations, or OpenMP and CUDA flags are all examples of flags that Kokkos configures and adds to your project. + +Modern CMake now automatically propagates flags through the `target_link_libraries` command. +Suppose you have a library `stencil` that needs to build with Kokkos. +Consider the following CMake code: + +```` +find_package(Kokkos) +add_library(stencil stencil.cpp) +target_link_libraries(stencil Kokkos::kokkos) +```` + +This locates the Kokkos package, adds your library, and tells CMake to link Kokkos to your library. +All public build flags get added automatically through the `target_link_libraries` command. +There is nothing to do. You can be happily oblivious to how Kokkos was configured. +Everything should just work. + +As a Kokkos developer who wants to add new public compiler flags, how do you ensure that CMake does this properly? Modern CMake works through targets and properties. +Each target has a set of standard properties: +* `INTERFACE_COMPILE_OPTIONS` contains all the compiler options that Kokkos should add to downstream projects +* `INTERFACE_INCLUDE_DIRECTORIES` contains all the directories downstream projects must include from Kokkos +* `INTERFACE_COMPILE_DEFINITIONS` contains the list of preprocessor `-D` flags +* `INTERFACE_LINK_LIBRARIES` contains all the libraries downstream projects need to link +* `INTERFACE_COMPILE_FEATURES` essentially adds compiler flags, but with extra complications. Features names are specific to CMake. More later. + +CMake makes it easy to append to these properties using: +* `target_compile_options(kokkos PUBLIC -fmyflag)` +* `target_include_directories(kokkos PUBLIC mySpecialFolder)` +* `target_compile_definitions(kokkos PUBLIC -DmySpecialFlag=0)` +* `target_link_libraries(kokkos PUBLIC mySpecialLibrary)` +* `target_compile_features(kokkos PUBLIC mySpecialFeature)` +Note that all of these use `PUBLIC`! Almost every Kokkos flag is not private to Kokkos, but must also be used by downstream projects. + + +### Compiler Features and Compiler Options +Compiler options are flags like `-fopenmp` that do not need to be "resolved." +The flag is either on or off. +Compiler features are more fine-grained and require conflicting requests to be resolved. +Suppose I have +```` +add_library(A a.cpp) +target_compile_features(A PUBLIC cxx_std_11) +```` +then another target +```` +add_library(B b.cpp) +target_compile_features(B PUBLIC cxx_std_14) +target_link_libraries(A B) +```` +I have requested two diferent features. +CMake understands the requests and knows that `cxx_std_11` is a subset of `cxx_std_14`. +CMake then picks C++14 for library `B`. +CMake would not have been able to do feature resolution if we had directly done: +```` +target_compile_options(A PUBLIC -std=c++11) +```` + +### Adding Kokkos Options +After configuring for the first time, +CMake creates a cache of configure variables in `CMakeCache.txt`. +Reconfiguring in the folder "restarts" from those variables. +All flags passed as `-DKokkos_SOME_OPTION=X` to `cmake` become variables in the cache. +All Kokkos options begin with camel case `Kokkos_` followed by an upper case option name. + +CMake best practice is to avoid cache variables, if possible. +In essence, you want the minimal amount of state cached between configurations. +And never, ever have behavior influenced by multiple cache variables. +If you want to change the Kokkos configuration, have a single unique variable that needs to be changed. +Never require two cache variables to be changed. + +Kokkos provides a function `KOKKOS_OPTION` for defining valid cache-level variables, +proofreading them, and defining local project variables. +The most common variables are called `Kokkos_ENABLE_X`, +for which a helper function `KOKKOS_ENABLE_OPTION` is provided, e.g. +```` +KOKKOS_ENABLE_OPTION(TESTS OFF "Whether to build tests") +```` +The function checks if `-DKokkos_ENABLE_TESTS` was given, +whether it was given with the wrong case, e.g. `-DKokkos_Enable_Tests`, +and then defines a regular (non-cache) variable `KOKKOS_ENABLE_TESTS` to `ON` or `OFF` +depending on the given default and whether the option was specified. + +### Defining Kokkos Config Macros + +Sometimes you may want to add `#define Kokkos_X` macros to the config header. +This is straightforward with CMake. +Suppose you want to define an optional macro `KOKKOS_SUPER_SCIENCE`. +Simply go into `KokkosCore_config.h.in` and add +```` +#cmakedefine KOKKOS_SUPER_SCIENCE +```` +I can either add +```` +KOKKOS_OPTION(SUPER_SCIENCE ON "Whether to do some super science") +```` +to directly set the variable as a command-line `-D` option. +Alternatively, based on other logic, I could add to a `CMakeLists.txt` +```` +SET(KOKKOS_SUPER_SCIENCE ON) +```` +If not set as a command-line option (cache variable), you must make sure the variable is visible in the top-level scope. +If set in a function, you would need: +```` +SET(KOKKOS_SUPER_SCIENCE ON PARENT_SCOPE) +```` + +### Third-Party Libraries +In much the same way that compiler flags transitively propagate to dependent projects, +modern CMake allows us to propagate dependent libraries. +If Kokkos depends on, e.g. `hwloc` the downstream project will also need to link `hwloc`. +There are three stages in adding a new third-party library (TPL): +* Finding: find the desired library on the system and verify the installation is correct +* Importing: create a CMake target, if necessary, that is compatible with `target_link_libraries`. This is mostly relevant for TPLs not installed with CMake. +* Exporting: make the desired library visible to downstream projects + +TPLs are somewhat complicated by whether the library was installed with CMake or some other build system. +If CMake, our lives are greatly simplified. We simply use `find_package` to locate the installed CMake project then call `target_link_libraries(kokkoscore PUBLIC/PRIVATE TPL)`. For libaries not installed with CMake, the process is a bit more complex. +It is up to the Kokkos developers to "convert" the library into a CMake target as if it had been installed as a valid modern CMake target with properties. +There are helper functions for simplifying the process of importing TPLs in Kokkos, but we walk through the process in detail to clearly illustrate the steps involved. + +#### TPL Search Order + +There are several options for where CMake could try to find a TPL. +If there are multiple installations of the same TPL on the system, +the search order is critical for making sure the correct TPL is found. +There are 3 possibilities that could be used: + +1. Default system paths like /usr +1. User-provided paths through options `_ROOT` and `Kokkos__DIR` +1. Additional paths not in the CMake default list or provided by the user that Kokkos decides to add. For example, Kokkos may query `nvcc` or `LD_LIBRARY_PATH` for where to find CUDA libraries. + +The following is the search order that Kokkos follows. Note: This differs from the default search order used by CMake `find_library` and `find_header`. CMake prefers default system paths over user-provided paths. +For Kokkos (and package managers in general), it is better to prefer user-provided paths since this usually indicates a specific version we want. + +1. `_ROOT` +1. `Kokkos__DIR` +1. Paths added by Kokkos CMake logic +1. Default system paths (if allowed) + +Default system paths are allowed in two cases. First, none of the other options are given so the only place to look is system paths. Second, if explicitly given permission, configure will look in system paths. +The rationale for this logic is that if you specify a custom location, you usually *only* want to look in that location. +If you do not find the TPL where you expect it, you should error out rather than grab another random match. + + +#### Finding TPLs + +If finding a TPL that is not a modern CMake project, refer to the `FindHWLOC.cmake` file in `cmake/Modules` for an example. +You will ususally need to verify expected headers with `find_path` +```` +find_path(TPL_INCLUDE_DIR mytpl.h PATHS "${KOKKOS_MYTPL_DIR}/include") +```` +This insures that the library header is in the expected include directory and defines the variable `TPL_INCLUDE_DIR` with a valid path if successful. +Similarly, you can verify a library +```` +find_library(TPL_LIBRARY mytpl PATHS "${KOKKOS_MYTPL_DIR/lib") +```` +that then defines the variable `TPL_LIBRARY` with a valid path if successful. +CMake provides a utility for checking if the `find_path` and `find_library` calls were successful that emulates the behavior of `find_package` for a CMake target. +```` +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MYTPL DEFAULT_MSG + MYTPL_INCLUDE_DIR MYTPL_LIBRARY) +```` +If the find failed, CMake will print standard error messages explaining the failure. + +#### Importing TPLs + +The installed TPL must be adapted into a CMake target. +CMake allows libraries to be added that are built externally as follows: +```` +add_library(Kokkos::mytpl UNKNOWN IMPORTED) +```` +Importantly, we use a `Kokkos::` namespace to avoid name conflicts and identify this specifically as the version imported by Kokkos. +Because we are importing a non-CMake target, we must populate all the target properties that would have been automatically populated for a CMake target. +```` +set_target_properties(Kokkos::mytpl PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MYTPL_INCLUDE_DIR}" + IMPORTED_LOCATION "${MYTPL_LIBRARY}" +) +```` + +#### Exporting TPLs + +Kokkos may now depend on the target `Kokkos::mytpl` as a `PUBLIC` library (remember building and using). +This means that downstream projects must also know about `Kokkos::myptl` - so Kokkos must export them. +In the `KokkosConfig.cmake.in` file, we need to add code like the following: +```` +set(MYTPL_LIBRARY @MYTPL_LIBRARY@) +set(MYTPL_INCLUDE_DIR @MYTPL_INCLUDE_DIR@) +add_library(Kokkos::mytpl UNKNOWN IMPORTED) +set_target_properties(Kokkos::mytpl PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${MYTPL_INCLUDE_DIR}" + IMPORTED_LOCATION "${MYTPL_LIBRARY}" +) +```` +If this looks familiar, that's because it is exactly the same code as above for importing the TPL. +Exporting a TPL really just means importing the TPL when Kokkos is loaded by an external project. +We will describe helper functions that simplify this process. + +#### Interface TPLs + +If a TPL is just a library and set of headers, we can make a simple `IMPORTED` target. +However, a TPL is actually completely flexible and need not be limited to just headers and libraries. +TPLs can configure compiler flags, linker flags, or multiple different libraries. +For this, we use a special type of CMake target: `INTERFACE` libraries. +These libraries don't build anything. +They simply populate properties that will configure flags for dependent targets. +We consider the example: +```` +add_library(PTHREAD INTERFACE) +target_compile_options(PTHREAD PUBLIC -pthread) +```` +Kokkos uses the compiler flag `-pthread` to define compiler macros for re-entrant functions rather than treating it simply as a library with header `pthread.h` and library `-lpthread`. +Any property can be configured, e.g. +```` +target_link_libraries(MYTPL ...) +```` +In contrast to imported TPLs which require direct modification of `KokkosConfig.cmake.in`, +we can use CMake's built-in export functions: +```` +INSTALL( + TARGETS MYTPL + EXPORT KokkosTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} +) +```` +These interface targets will be automatically populated in the config file. + +#### Linking the TPL +After finishing the import process, it still remains to link the imported target as needed. +For example, +```` +target_link_libraries(kokkoscore PUBLIC Kokkos::HWLOC) +```` +The complexity of which includes, options, and libraries the TPL requires +should be encapsulated in the CMake target. + +#### TPL Helper Functions +##### KOKKOS_IMPORT_TPL +This function can be invoked as, e.g. +```` +KOKKOS_IMPORT_TPL(HWLOC) +```` +This function checks if the TPL was enabled by a `-DKokkos_ENABLE_HWLOC=On` flag. +If so, it calls `find_package(TPLHWLOC)`. +This invokes the file `FindTPLHWLOC.cmake` which should be contained in the `cmake/Modules` folder. +If successful, another function `KOKKOS_EXPORT_CMAKE_TPL` gets invoked. +This automatically adds all the necessary import commands to `KokkosConfig.cmake`. + +##### KOKKOS_FIND_IMPORTED +Inside a `FindTPLX.cmake` file, the simplest way to import a library is to call, e.g. +```` +KOKKOS_FIND_IMPORTED(HWLOC LIBRARY hwloc HEADER hwloc.h) +```` +This finds the location of the library and header and creates an imported target `Kokkos::HWLOC` +that can be linked against. +The library/header find can be guided with `-DHWLOC_ROOT=` or `-DKokkos_HWLOC_DIR=` during CMake configure. +These both specify the install prefix. + +##### KOKKOS_LINK_TPL +This function checks if the TPL has been enabled. +If so, it links a given library against the imported (or interface) TPL target. + +##### KOKKOS_CREATE_IMPORTED_TPL +This helper function is best understood by reading the actual code. +This function takes arguments specifying the properties and creates the actual TPL target. +The most important thing to understand for this function is whether you call this function with the optional `INTERFACE` keyword. +This tells the project to either create the target as an imported target or interface target, as discussed above. + +##### KOKKOS_EXPORT_CMAKE_TPL +Even if the TPL just loads a valid CMake target, we still must "export" it into the config file. +When Kokkos is loaded by a downstream project, this TPL must be loaded. +Calling this function simply appends text recording the location where the TPL was found +and adding a `find_dependency(...)` call that will reload the CMake target. + +### The Great TriBITS Compromise + +TriBITS was a masterpiece of CMake version 2 before the modern CMake idioms of building and using. +TriBITS greatly limited verbosity of CMake files, handled complicated dependency trees between packages, and handled automatically setting up include and linker paths for dependent libraries. + +Kokkos is now used by numerous projects that don't (and won't) depend on TriBITS for their build systems. +Kokkos has to work outside of TriBITS and provide a standard CMake 3+ build system. +At the same time, Kokkos is used by numerous projects that depend on TriBITS and don't (and won't) switch to a standard CMake 3+ build system. + +Instead of calling functions `TRIBITS_X(...)`, the CMake calls wrapper functions `KOKKOS_X(...)`. +If TriBITS is available (as in Trilinos), `KOKKOS_X` will just be a thin wrapper around `TRIBITS_X`. +If TriBITS is not available, Kokkos maps `KOKKOS_X` calls to native CMake that complies with CMake 3 idioms. +For the time being, this seems the most sensible way to handle the competing requirements of a standalone modern CMake and TriBITS build system. + +##### [LICENSE](https://github.com/kokkos/kokkos/blob/devel/LICENSE) + +[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](https://opensource.org/licenses/BSD-3-Clause) + +Under the terms of Contract DE-NA0003525 with NTESS, +the U.S. Government retains certain rights in this software. diff --git a/lib/kokkos/cmake/compile_tests/clang_omp.cpp b/lib/kokkos/cmake/compile_tests/clang_omp.cpp new file mode 100644 index 0000000000..ce3bbfb262 --- /dev/null +++ b/lib/kokkos/cmake/compile_tests/clang_omp.cpp @@ -0,0 +1,9 @@ +#include + +int main(int argc, char** argv) { + int thr = omp_get_num_threads(); + if (thr > 0) + return thr; + else + return 0; +} diff --git a/lib/kokkos/cmake/compile_tests/pthread.cpp b/lib/kokkos/cmake/compile_tests/pthread.cpp new file mode 100644 index 0000000000..3b13f7ba35 --- /dev/null +++ b/lib/kokkos/cmake/compile_tests/pthread.cpp @@ -0,0 +1,10 @@ +#include + +void* kokkos_test(void* args) { return args; } + +int main(void) { + pthread_t thread; + pthread_create(&thread, NULL, kokkos_test, NULL); + pthread_join(thread, NULL); + return 0; +} diff --git a/lib/kokkos/cmake/cray.cmake b/lib/kokkos/cmake/cray.cmake new file mode 100644 index 0000000000..08912f5130 --- /dev/null +++ b/lib/kokkos/cmake/cray.cmake @@ -0,0 +1,9 @@ + + +function(kokkos_set_cray_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + SET(KOKKOS_CXX_STANDARD_FLAG "-hstd=c++${FULL_LC_STANDARD}", PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMDIATE_STANDARD_FLAG "-hstd=c++${INT_LC_STANDARD}" PARENT_SCOPE) +endfunction() + diff --git a/lib/kokkos/cmake/deps/CUDA.cmake b/lib/kokkos/cmake/deps/CUDA.cmake index 801c20067b..4876bca259 100644 --- a/lib/kokkos/cmake/deps/CUDA.cmake +++ b/lib/kokkos/cmake/deps/CUDA.cmake @@ -73,7 +73,7 @@ IF(NOT _CUDA_FAILURE) GLOBAL_SET(TPL_CUDA_LIBRARY_DIRS) GLOBAL_SET(TPL_CUDA_INCLUDE_DIRS ${CUDA_TOOLKIT_INCLUDE}) GLOBAL_SET(TPL_CUDA_LIBRARIES ${CUDA_CUDART_LIBRARY} ${CUDA_cublas_LIBRARY} ${CUDA_cufft_LIBRARY}) - TIBITS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) + KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) ELSE() SET(TPL_ENABLE_CUDA OFF) ENDIF() diff --git a/lib/kokkos/cmake/deps/CUSPARSE.cmake b/lib/kokkos/cmake/deps/CUSPARSE.cmake index 6f26d857c0..b2420d1168 100644 --- a/lib/kokkos/cmake/deps/CUSPARSE.cmake +++ b/lib/kokkos/cmake/deps/CUSPARSE.cmake @@ -59,6 +59,6 @@ # GLOBAL_SET(TPL_CUSPARSE_LIBRARY_DIRS) # GLOBAL_SET(TPL_CUSPARSE_INCLUDE_DIRS ${TPL_CUDA_INCLUDE_DIRS}) # GLOBAL_SET(TPL_CUSPARSE_LIBRARIES ${CUDA_cusparse_LIBRARY}) -# TIBITS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) +# KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(CUSPARSE) #ENDIF() diff --git a/lib/kokkos/cmake/deps/HWLOC.cmake b/lib/kokkos/cmake/deps/HWLOC.cmake index 275abd3a5d..ed89c8c1e5 100644 --- a/lib/kokkos/cmake/deps/HWLOC.cmake +++ b/lib/kokkos/cmake/deps/HWLOC.cmake @@ -64,7 +64,7 @@ # Version: 1.3 # -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC +KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC REQUIRED_HEADERS hwloc.h REQUIRED_LIBS_NAMES "hwloc" ) diff --git a/lib/kokkos/cmake/deps/Pthread.cmake b/lib/kokkos/cmake/deps/Pthread.cmake index 46d0a939ca..5f835fc300 100644 --- a/lib/kokkos/cmake/deps/Pthread.cmake +++ b/lib/kokkos/cmake/deps/Pthread.cmake @@ -74,9 +74,9 @@ IF(USE_THREADS) SET(TPL_Pthread_INCLUDE_DIRS "") SET(TPL_Pthread_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") SET(TPL_Pthread_LIBRARY_DIRS "") - TIBITS_CREATE_IMPORTED_TPL_LIBRARY(Pthread) + KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(Pthread) ELSE() - TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread + KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread REQUIRED_HEADERS pthread.h REQUIRED_LIBS_NAMES pthread ) diff --git a/lib/kokkos/cmake/deps/QTHREADS.cmake b/lib/kokkos/cmake/deps/QTHREADS.cmake deleted file mode 100644 index c312f2590b..0000000000 --- a/lib/kokkos/cmake/deps/QTHREADS.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# @HEADER -# ************************************************************************ -# -# Trilinos: An Object-Oriented Solver Framework -# Copyright (2001) Sandia Corporation -# -# -# Copyright (2001) Sandia Corporation. Under the terms of Contract -# DE-AC04-94AL85000, there is a non-exclusive license for use of this -# work by or on behalf of the U.S. Government. Export of this program -# may require a license from the United States Government. -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the Corporation nor the names of the -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# NOTICE: The United States Government is granted for itself and others -# acting on its behalf a paid-up, nonexclusive, irrevocable worldwide -# license in this data to reproduce, prepare derivative works, and -# perform publicly and display publicly. Beginning five (5) years from -# July 25, 2001, the United States Government is granted for itself and -# others acting on its behalf a paid-up, nonexclusive, irrevocable -# worldwide license in this data to reproduce, prepare derivative works, -# distribute copies to the public, perform publicly and display -# publicly, and to permit others to do so. -# -# NEITHER THE UNITED STATES GOVERNMENT, NOR THE UNITED STATES DEPARTMENT -# OF ENERGY, NOR SANDIA CORPORATION, NOR ANY OF THEIR EMPLOYEES, MAKES -# ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL LIABILITY OR -# RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY -# INFORMATION, APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS -# THAT ITS USE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS. -# -# ************************************************************************ -# @HEADER - - -#----------------------------------------------------------------------------- -# Hardware locality detection and control library. -# -# Acquisition information: -# Date checked: July 2014 -# Checked by: H. Carter Edwards -# Source: https://code.google.com/p/qthreads -# - -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( QTHREADS - REQUIRED_HEADERS qthread.h - REQUIRED_LIBS_NAMES "qthread" - ) diff --git a/lib/kokkos/cmake/fake_tribits.cmake b/lib/kokkos/cmake/fake_tribits.cmake new file mode 100644 index 0000000000..26948d2cfb --- /dev/null +++ b/lib/kokkos/cmake/fake_tribits.cmake @@ -0,0 +1,338 @@ +#These are tribits wrappers used by all projects in the Kokkos ecosystem + +INCLUDE(CMakeParseArguments) +INCLUDE(CTest) + +cmake_policy(SET CMP0054 NEW) + +FUNCTION(ASSERT_DEFINED VARS) + FOREACH(VAR ${VARS}) + IF(NOT DEFINED ${VAR}) + MESSAGE(SEND_ERROR "Error, the variable ${VAR} is not defined!") + ENDIF() + ENDFOREACH() +ENDFUNCTION() + +MACRO(KOKKOS_ADD_OPTION_AND_DEFINE USER_OPTION_NAME MACRO_DEFINE_NAME DOCSTRING DEFAULT_VALUE ) +SET( ${USER_OPTION_NAME} "${DEFAULT_VALUE}" CACHE BOOL "${DOCSTRING}" ) +IF(NOT ${MACRO_DEFINE_NAME} STREQUAL "") + IF(${USER_OPTION_NAME}) + GLOBAL_SET(${MACRO_DEFINE_NAME} ON) + ELSE() + GLOBAL_SET(${MACRO_DEFINE_NAME} OFF) + ENDIF() +ENDIF() +ENDMACRO() + +MACRO(GLOBAL_RESET VARNAME) + SET(${VARNAME} "" CACHE INTERNAL "" FORCE) +ENDMACRO() + +MACRO(GLOBAL_OVERWRITE VARNAME VALUE TYPE) + SET(${VARNAME} ${VALUE} CACHE ${TYPE} "" FORCE) +ENDMACRO() + +IF (NOT KOKKOS_HAS_TRILINOS) +MACRO(APPEND_GLOB VAR) + FILE(GLOB LOCAL_TMP_VAR ${ARGN}) + LIST(APPEND ${VAR} ${LOCAL_TMP_VAR}) +ENDMACRO() + +MACRO(GLOBAL_SET VARNAME) + SET(${VARNAME} ${ARGN} CACHE INTERNAL "" FORCE) +ENDMACRO() + +FUNCTION(VERIFY_EMPTY CONTEXT) +if(${ARGN}) +MESSAGE(FATAL_ERROR "Kokkos does not support all of Tribits. Unhandled arguments in ${CONTEXT}:\n${ARGN}") +endif() +ENDFUNCTION() + +MACRO(PREPEND_GLOBAL_SET VARNAME) + ASSERT_DEFINED(${VARNAME}) + GLOBAL_SET(${VARNAME} ${ARGN} ${${VARNAME}}) +ENDMACRO() + +MACRO(PREPEND_TARGET_SET VARNAME TARGET_NAME TYPE) + IF(TYPE STREQUAL "REQUIRED") + SET(REQUIRED TRUE) + ELSE() + SET(REQUIRED FALSE) + ENDIF() + IF(TARGET ${TARGET_NAME}) + PREPEND_GLOBAL_SET(${VARNAME} ${TARGET_NAME}) + ELSE() + IF(REQUIRED) + MESSAGE(FATAL_ERROR "Missing dependency ${TARGET_NAME}") + ENDIF() + ENDIF() +ENDMACRO() +endif() + + +FUNCTION(KOKKOS_CONFIGURE_FILE PACKAGE_NAME_CONFIG_FILE) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_CONFIGURE_FILE(${PACKAGE_NAME_CONFIG_FILE}) + else() + # Configure the file + CONFIGURE_FILE( + ${PACKAGE_SOURCE_DIR}/cmake/${PACKAGE_NAME_CONFIG_FILE}.in + ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME_CONFIG_FILE} + ) + endif() +ENDFUNCTION() + +MACRO(ADD_INTERFACE_LIBRARY LIB_NAME) + FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "") + ADD_LIBRARY(${LIB_NAME} STATIC ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp) + SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES INTERFACE TRUE) +ENDMACRO() + +IF(NOT TARGET check) + ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) +ENDIF() + +FUNCTION(KOKKOS_ADD_TEST) + if (KOKKOS_HAS_TRILINOS) + CMAKE_PARSE_ARGUMENTS(TEST + "" + "EXE;NAME" + "" + ${ARGN}) + IF(TEST_EXE) + SET(EXE_ROOT ${TEST_EXE}) + ELSE() + SET(EXE_ROOT ${TEST_NAME}) + ENDIF() + + TRIBITS_ADD_TEST( + ${EXE_ROOT} + NAME ${TEST_NAME} + ${ARGN} + COMM serial mpi + NUM_MPI_PROCS 1 + ${TEST_UNPARSED_ARGUMENTS} + ) + else() + CMAKE_PARSE_ARGUMENTS(TEST + "WILL_FAIL" + "FAIL_REGULAR_EXPRESSION;PASS_REGULAR_EXPRESSION;EXE;NAME" + "CATEGORIES;CMD_ARGS" + ${ARGN}) + IF(TEST_EXE) + SET(EXE ${TEST_EXE}) + ELSE() + SET(EXE ${TEST_NAME}) + ENDIF() + IF(WIN32) + ADD_TEST(NAME ${TEST_NAME} WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} COMMAND ${EXE}${CMAKE_EXECUTABLE_SUFFIX} ${TEST_CMD_ARGS}) + ELSE() + ADD_TEST(NAME ${TEST_NAME} COMMAND ${EXE} ${TEST_CMD_ARGS}) + ENDIF() + IF(TEST_WILL_FAIL) + SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES WILL_FAIL ${TEST_WILL_FAIL}) + ENDIF() + IF(TEST_FAIL_REGULAR_EXPRESSION) + SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION ${TEST_FAIL_REGULAR_EXPRESSION}) + ENDIF() + IF(TEST_PASS_REGULAR_EXPRESSION) + SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES PASS_REGULAR_EXPRESSION ${TEST_PASS_REGULAR_EXPRESSION}) + ENDIF() + VERIFY_EMPTY(KOKKOS_ADD_TEST ${TEST_UNPARSED_ARGUMENTS}) + endif() +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_ADVANCED_TEST) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_ADVANCED_TEST(${ARGN}) + else() + # TODO Write this + endif() +ENDFUNCTION() + +MACRO(KOKKOS_CREATE_IMPORTED_TPL_LIBRARY TPL_NAME) + ADD_INTERFACE_LIBRARY(TPL_LIB_${TPL_NAME}) + TARGET_LINK_LIBRARIES(TPL_LIB_${TPL_NAME} LINK_PUBLIC ${TPL_${TPL_NAME}_LIBRARIES}) + TARGET_INCLUDE_DIRECTORIES(TPL_LIB_${TPL_NAME} INTERFACE ${TPL_${TPL_NAME}_INCLUDE_DIRS}) +ENDMACRO() + +FUNCTION(KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES TPL_NAME) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES(${TPL_NAME} ${ARGN}) + else() + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "REQUIRED_HEADERS;REQUIRED_LIBS_NAMES" + ${ARGN}) + + SET(_${TPL_NAME}_ENABLE_SUCCESS TRUE) + IF (PARSE_REQUIRED_LIBS_NAMES) + FIND_LIBRARY(TPL_${TPL_NAME}_LIBRARIES NAMES ${PARSE_REQUIRED_LIBS_NAMES}) + IF(NOT TPL_${TPL_NAME}_LIBRARIES) + SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) + ENDIF() + ENDIF() + IF (PARSE_REQUIRED_HEADERS) + FIND_PATH(TPL_${TPL_NAME}_INCLUDE_DIRS NAMES ${PARSE_REQUIRED_HEADERS}) + IF(NOT TPL_${TPL_NAME}_INCLUDE_DIRS) + SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) + ENDIF() + ENDIF() + IF (_${TPL_NAME}_ENABLE_SUCCESS) + KOKKOS_CREATE_IMPORTED_TPL_LIBRARY(${TPL_NAME}) + ENDIF() + VERIFY_EMPTY(KOKKOS_CREATE_IMPORTED_TPL_LIBRARY ${PARSE_UNPARSED_ARGUMENTS}) + endif() +ENDFUNCTION() + +MACRO(KOKKOS_TARGET_COMPILE_OPTIONS TARGET) +if(KOKKOS_HAS_TRILINOS) + TARGET_COMPILE_OPTIONS(${TARGET} ${ARGN}) +else() + TARGET_COMPILE_OPTIONS(${TARGET} ${ARGN}) +endif() +ENDMACRO() + + +MACRO(KOKKOS_EXCLUDE_AUTOTOOLS_FILES) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_EXCLUDE_AUTOTOOLS_FILES() + else() + #do nothing + endif() +ENDMACRO() + +FUNCTION(KOKKOS_LIB_TYPE LIB RET) +GET_TARGET_PROPERTY(PROP ${LIB} TYPE) +IF (${PROP} STREQUAL "INTERFACE_LIBRARY") + SET(${RET} "INTERFACE" PARENT_SCOPE) +ELSE() + SET(${RET} "PUBLIC" PARENT_SCOPE) +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_TARGET_INCLUDE_DIRECTORIES TARGET) +IF(KOKKOS_HAS_TRILINOS) + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + #don't trust tribits to do this correctly - but need to add package name + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${INCTYPE} ${ARGN}) +ELSEIF(TARGET ${TARGET}) + #the target actually exists - this means we are doing separate libs + #or this a test library + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${INCTYPE} ${ARGN}) +ELSE() + GET_PROPERTY(LIBS GLOBAL PROPERTY KOKKOS_LIBRARIES_NAMES) + IF (${TARGET} IN_LIST LIBS) + SET_PROPERTY(GLOBAL APPEND PROPERTY KOKKOS_LIBRARY_INCLUDES ${ARGN}) + ELSE() + MESSAGE(FATAL_ERROR "Trying to set include directories on unknown target ${TARGET}") + ENDIF() +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_LINK_INTERNAL_LIBRARY TARGET DEPLIB) +IF(KOKKOS_HAS_TRILINOS) + #do nothing +ELSE() + SET(options INTERFACE) + SET(oneValueArgs) + SET(multiValueArgs) + CMAKE_PARSE_ARGUMENTS(PARSE + "INTERFACE" + "" + "" + ${ARGN}) + SET(LINK_TYPE) + IF(PARSE_INTERFACE) + SET(LINK_TYPE INTERFACE) + ELSE() + SET(LINK_TYPE PUBLIC) + ENDIF() + TARGET_LINK_LIBRARIES(${TARGET} ${LINK_TYPE} ${DEPLIB}) + VERIFY_EMPTY(KOKKOS_LINK_INTERNAL_LIBRARY ${PARSE_UNPARSED_ARGUMENTS}) +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_TEST_LIBRARY NAME) +IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_LIBRARY(${NAME} ${ARGN} TESTONLY + ADDED_LIB_TARGET_NAME_OUT ${NAME} + ) +ELSE() + SET(oneValueArgs) + SET(multiValueArgs HEADERS SOURCES) + + CMAKE_PARSE_ARGUMENTS(PARSE + "STATIC;SHARED" + "" + "HEADERS;SOURCES" + ${ARGN}) + + IF(PARSE_HEADERS) + LIST(REMOVE_DUPLICATES PARSE_HEADERS) + ENDIF() + IF(PARSE_SOURCES) + LIST(REMOVE_DUPLICATES PARSE_SOURCES) + ENDIF() + ADD_LIBRARY(${NAME} ${PARSE_SOURCES}) + target_link_libraries( + ${NAME} + PUBLIC kokkos + ) +ENDIF() +ENDFUNCTION() + + +FUNCTION(KOKKOS_TARGET_COMPILE_DEFINITIONS) + IF (KOKKOS_HAS_TRILINOS) + TARGET_COMPILE_DEFINITIONS(${TARGET} ${ARGN}) + ELSE() + TARGET_COMPILE_DEFINITIONS(${TARGET} ${ARGN}) + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_INCLUDE_DIRECTORIES) +IF(KOKKOS_HAS_TRILINOS) + TRIBITS_INCLUDE_DIRECTORIES(${ARGN}) +ELSE() + CMAKE_PARSE_ARGUMENTS( + INC + "REQUIRED_DURING_INSTALLATION_TESTING" + "" + "" + ${ARGN} + ) + INCLUDE_DIRECTORIES(${INC_UNPARSED_ARGUMENTS}) +ENDIF() +ENDFUNCTION() + + +MACRO(KOKKOS_ADD_COMPILE_OPTIONS) +ADD_COMPILE_OPTIONS(${ARGN}) +ENDMACRO() + +MACRO(PRINTALL match) +get_cmake_property(_variableNames VARIABLES) +list (SORT _variableNames) +foreach (_variableName ${_variableNames}) + if("${_variableName}" MATCHES "${match}") + message(STATUS "${_variableName}=${${_variableName}}") + endif() +endforeach() +ENDMACRO() + +MACRO(SET_GLOBAL_REPLACE SUBSTR VARNAME) + STRING(REPLACE ${SUBSTR} ${${VARNAME}} TEMP) + GLOBAL_SET(${VARNAME} ${TEMP}) +ENDMACRO() + +FUNCTION(GLOBAL_APPEND VARNAME) + #We make this a function since we are setting variables + #and want to use scope to avoid overwriting local variables + SET(TEMP ${${VARNAME}}) + LIST(APPEND TEMP ${ARGN}) + GLOBAL_SET(${VARNAME} ${TEMP}) +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/gnu.cmake b/lib/kokkos/cmake/gnu.cmake new file mode 100644 index 0000000000..aa11fe87b1 --- /dev/null +++ b/lib/kokkos/cmake/gnu.cmake @@ -0,0 +1,23 @@ + +FUNCTION(kokkos_set_gnu_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + # The following three blocks of code were copied from + # /Modules/Compiler/Intel-CXX.cmake from CMake 3.7.2 and then modified. + IF(CMAKE_CXX_SIMULATE_ID STREQUAL MSVC) + SET(_std -Qstd) + SET(_ext c++) + ELSE() + SET(_std -std) + SET(_ext gnu++) + ENDIF() + + IF (CMAKE_CXX_EXTENSIONS) + SET(KOKKOS_CXX_STANDARD_FLAG "-std=gnu++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG "-std=gnu++${INT_LC_STANDARD}" PARENT_SCOPE) + ELSE() + SET(KOKKOS_CXX_STANDARD_FLAG "-std=c++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG "-std=c++${INT_LC_STANDARD}" PARENT_SCOPE) + ENDIF() +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/intel.cmake b/lib/kokkos/cmake/intel.cmake new file mode 100644 index 0000000000..f36f01d8ca --- /dev/null +++ b/lib/kokkos/cmake/intel.cmake @@ -0,0 +1,30 @@ + +FUNCTION(kokkos_set_intel_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + # The following three blocks of code were copied from + # /Modules/Compiler/Intel-CXX.cmake from CMake 3.7.2 and then modified. + IF(CMAKE_CXX_SIMULATE_ID STREQUAL MSVC) + SET(_std -Qstd) + SET(_ext c++) + ELSE() + SET(_std -std) + SET(_ext gnu++) + ENDIF() + + IF(NOT KOKKOS_CXX_STANDARD STREQUAL 11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) + #There is no gnu++14 value supported; figure out what to do. + SET(KOKKOS_CXX_STANDARD_FLAG "${_std}=c++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG "${_std}=c++${INT_LC_STANDARD}" PARENT_SCOPE) + ELSEIF(KOKKOS_CXX_STANDARD STREQUAL 11 AND NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) + IF (CMAKE_CXX_EXTENSIONS) + SET(KOKKOS_CXX_STANDARD_FLAG "${_std}=${_ext}c++11" PARENT_SCOPE) + ELSE() + SET(KOKKOS_CXX_STANDARD_FLAG "${_std}=c++11" PARENT_SCOPE) + ENDIF() + ELSE() + MESSAGE(FATAL_ERROR "Intel compiler version too low - need 13.0 for C++11 and 15.0 for C++14") + ENDIF() + +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/kokkos_arch.cmake b/lib/kokkos/cmake/kokkos_arch.cmake new file mode 100644 index 0000000000..c33247c955 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_arch.cmake @@ -0,0 +1,438 @@ + +FUNCTION(KOKKOS_ARCH_OPTION SUFFIX DEV_TYPE DESCRIPTION) + #all optimizations off by default + KOKKOS_OPTION(ARCH_${SUFFIX} OFF BOOL "Optimize for ${DESCRIPTION} (${DEV_TYPE})") + IF (KOKKOS_ARCH_${SUFFIX}) + LIST(APPEND KOKKOS_ENABLED_ARCH_LIST ${SUFFIX}) + SET(KOKKOS_ENABLED_ARCH_LIST ${KOKKOS_ENABLED_ARCH_LIST} PARENT_SCOPE) + ENDIF() + SET(KOKKOS_ARCH_${SUFFIX} ${KOKKOS_ARCH_${SUFFIX}} PARENT_SCOPE) +ENDFUNCTION() + +FUNCTION(ARCH_FLAGS) + SET(COMPILERS NVIDIA PGI XL DEFAULT Cray Intel Clang AppleClang GNU) + CMAKE_PARSE_ARGUMENTS( + PARSE + "LINK_ONLY;COMPILE_ONLY" + "" + "${COMPILERS}" + ${ARGN}) + + SET(COMPILER ${KOKKOS_CXX_COMPILER_ID}) + + SET(FLAGS) + SET(NEW_COMPILE_OPTIONS) + SET(NEW_XCOMPILER_OPTIONS) + SET(NEW_LINK_OPTIONS) + LIST(APPEND NEW_XCOMPILER_OPTIONS ${KOKKOS_XCOMPILER_OPTIONS}) + LIST(APPEND NEW_COMPILE_OPTIONS ${KOKKOS_COMPILE_OPTIONS}) + LIST(APPEND NEW_LINK_OPTIONS ${KOKKOS_LINK_OPTIONS}) + FOREACH(COMP ${COMPILERS}) + IF (COMPILER STREQUAL "${COMP}") + IF (PARSE_${COMPILER}) + IF (NOT "${PARSE_${COMPILER}}" STREQUAL "NO-VALUE-SPECIFIED") + SET(FLAGS ${PARSE_${COMPILER}}) + ENDIF() + ELSEIF(PARSE_DEFAULT) + SET(FLAGS ${PARSE_DEFAULT}) + ENDIF() + ENDIF() + ENDFOREACH() + + IF (NOT LINK_ONLY) + # The funky logic here is for future handling of argument deduplication + # If we naively pass multiple -Xcompiler flags to target_compile_options + # -Xcompiler will get deduplicated and break the build + IF ("-Xcompiler" IN_LIST FLAGS) + LIST(REMOVE_ITEM FLAGS "-Xcompiler") + GLOBAL_APPEND(KOKKOS_XCOMPILER_OPTIONS ${FLAGS}) + ELSE() + GLOBAL_APPEND(KOKKOS_COMPILE_OPTIONS ${FLAGS}) + ENDIF() + ENDIF() + + IF (NOT COMPILE_ONLY) + GLOBAL_APPEND(KOKKOS_LINK_OPTIONS ${FLAGS}) + ENDIF() +ENDFUNCTION() + +# Make sure devices and compiler ID are done +KOKKOS_CFG_DEPENDS(ARCH COMPILER_ID) +KOKKOS_CFG_DEPENDS(ARCH DEVICES) +KOKKOS_CFG_DEPENDS(ARCH OPTIONS) + + +#------------------------------------------------------------------------------- +# List of possible host architectures. +#------------------------------------------------------------------------------- +SET(KOKKOS_ARCH_LIST) + + +KOKKOS_DEPRECATED_LIST(ARCH ARCH) +KOKKOS_ARCH_OPTION(AMDAVX HOST "AMD chip") +KOKKOS_ARCH_OPTION(ARMV80 HOST "ARMv8.0 Compatible CPU") +KOKKOS_ARCH_OPTION(ARMV81 HOST "ARMv8.1 Compatible CPU") +KOKKOS_ARCH_OPTION(ARMV8_THUNDERX HOST "ARMv8 Cavium ThunderX CPU") +KOKKOS_ARCH_OPTION(ARMV8_THUNDERX2 HOST "ARMv8 Cavium ThunderX2 CPU") +KOKKOS_ARCH_OPTION(WSM HOST "Intel Westmere CPU") +KOKKOS_ARCH_OPTION(SNB HOST "Intel Sandy/Ivy Bridge CPUs") +KOKKOS_ARCH_OPTION(HSW HOST "Intel Haswell CPUs") +KOKKOS_ARCH_OPTION(BDW HOST "Intel Broadwell Xeon E-class CPUs") +KOKKOS_ARCH_OPTION(SKX HOST "Intel Sky Lake Xeon E-class HPC CPUs (AVX512)") +KOKKOS_ARCH_OPTION(KNC HOST "Intel Knights Corner Xeon Phi") +KOKKOS_ARCH_OPTION(KNL HOST "Intel Knights Landing Xeon Phi") +KOKKOS_ARCH_OPTION(BGQ HOST "IBM Blue Gene Q") +KOKKOS_ARCH_OPTION(POWER7 HOST "IBM POWER7 CPUs") +KOKKOS_ARCH_OPTION(POWER8 HOST "IBM POWER8 CPUs") +KOKKOS_ARCH_OPTION(POWER9 HOST "IBM POWER9 CPUs") +KOKKOS_ARCH_OPTION(KEPLER30 GPU "NVIDIA Kepler generation CC 3.0") +KOKKOS_ARCH_OPTION(KEPLER32 GPU "NVIDIA Kepler generation CC 3.2") +KOKKOS_ARCH_OPTION(KEPLER35 GPU "NVIDIA Kepler generation CC 3.5") +KOKKOS_ARCH_OPTION(KEPLER37 GPU "NVIDIA Kepler generation CC 3.7") +KOKKOS_ARCH_OPTION(MAXWELL50 GPU "NVIDIA Maxwell generation CC 5.0") +KOKKOS_ARCH_OPTION(MAXWELL52 GPU "NVIDIA Maxwell generation CC 5.2") +KOKKOS_ARCH_OPTION(MAXWELL53 GPU "NVIDIA Maxwell generation CC 5.3") +KOKKOS_ARCH_OPTION(PASCAL60 GPU "NVIDIA Pascal generation CC 6.0") +KOKKOS_ARCH_OPTION(PASCAL61 GPU "NVIDIA Pascal generation CC 6.1") +KOKKOS_ARCH_OPTION(VOLTA70 GPU "NVIDIA Volta generation CC 7.0") +KOKKOS_ARCH_OPTION(VOLTA72 GPU "NVIDIA Volta generation CC 7.2") +KOKKOS_ARCH_OPTION(TURING75 GPU "NVIDIA Turing generation CC 7.5") +KOKKOS_ARCH_OPTION(EPYC HOST "AMD Epyc architecture") + + +IF (KOKKOS_ENABLE_CUDA) + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_KEPLER30 OR KOKKOS_ARCH_KEPLER32 OR KOKKOS_ARCH_KEPLER35 OR KOKKOS_ARCH_KEPLER37) + SET(KOKKOS_ARCH_KEPLER ON) + ENDIF() + + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_MAXWELL50 OR KOKKOS_ARCH_MAXWELL52 OR KOKKOS_ARCH_MAXWELL53) + SET(KOKKOS_ARCH_MAXWELL ON) + ENDIF() + + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_PASCAL60 OR KOKKOS_ARCH_PASCAL61) + SET(KOKKOS_ARCH_PASCAL ON) + ENDIF() + + #Regardless of version, make sure we define the general architecture name + IF (KOKKOS_ARCH_VOLTA70 OR KOKKOS_ARCH_VOLTA72) + SET(KOKKOS_ARCH_VOLTA ON) + ENDIF() +ENDIF() + + + +IF(KOKKOS_ENABLE_COMPILER_WARNINGS) + SET(COMMON_WARNINGS + "-Wall" "-Wshadow" "-pedantic" + "-Wsign-compare" "-Wtype-limits" "-Wuninitialized") + + SET(GNU_WARNINGS "-Wempty-body" "-Wclobbered" "-Wignored-qualifiers" + ${COMMON_WARNINGS}) + + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + GNU ${GNU_WARNINGS} + DEFAULT ${COMMON_WARNINGS} + ) +ENDIF() + + +#------------------------------- KOKKOS_CUDA_OPTIONS --------------------------- +GLOBAL_RESET(KOKKOS_CUDA_OPTIONS) +# Construct the Makefile options +IF (KOKKOS_ENABLE_CUDA_LAMBDA) + IF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS "-expt-extended-lambda") + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_CUDA_CONSTEXPR) + IF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS "-expt-relaxed-constexpr") + ENDIF() +ENDIF() + +IF (KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + SET(CUDA_ARCH_FLAG "--cuda-gpu-arch") + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS -x cuda) + IF (KOKKOS_ENABLE_CUDA) + SET(KOKKOS_IMPL_CUDA_CLANG_WORKAROUND ON CACHE BOOL "enable CUDA Clang workarounds" FORCE) + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + SET(CUDA_ARCH_FLAG "-arch") +ENDIF() + +IF (KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + STRING(TOUPPER "${CMAKE_BUILD_TYPE}" _UPPERCASE_CMAKE_BUILD_TYPE) + IF (KOKKOS_ENABLE_DEBUG OR _UPPERCASE_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS -lineinfo) + ENDIF() + UNSET(_UPPERCASE_CMAKE_BUILD_TYPE) + IF (KOKKOS_CXX_COMPILER_VERSION VERSION_GREATER 9.0 OR KOKKOS_CXX_COMPILER_VERSION VERSION_EQUAL 9.0) + GLOBAL_APPEND(KOKKOS_CUDAFE_OPTIONS --diag_suppress=esa_on_defaulted_function_ignored) + ENDIF() +ENDIF() + +IF(KOKKOS_ENABLE_OPENMP) + IF (KOKKOS_CXX_COMPILER_ID STREQUAL AppleClang) + MESSAGE(FATAL_ERROR "Apple Clang does not support OpenMP. Use native Clang instead") + ENDIF() + ARCH_FLAGS( + Clang -fopenmp=libomp + PGI -mp + NVIDIA -Xcompiler -fopenmp + Cray NO-VALUE-SPECIFIED + XL -qsmp=omp + DEFAULT -fopenmp + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV80) + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -march=armv8-a + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV81) + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -march=armv8.1-a + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV8_THUNDERX) + SET(KOKKOS_ARCH_ARMV80 ON) #Not a cache variable + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -march=armv8-a -mtune=thunderx + ) +ENDIF() + +IF (KOKKOS_ARCH_ARMV8_THUNDERX2) + SET(KOKKOS_ARCH_ARMV81 ON) #Not a cache variable + ARCH_FLAGS( + Cray NO-VALUE-SPECIFIED + PGI NO-VALUE-SPECIFIED + DEFAULT -mcpu=thunderx2t99 -mtune=thunderx2t99 + ) +ENDIF() + +IF (KOKKOS_ARCH_EPYC) + ARCH_FLAGS( + Intel -mavx2 + DEFAULT -march=znver1 -mtune=znver1 + ) + SET(KOKKOS_ARCH_AMD_EPYC ON) + SET(KOKKOS_ARCH_AMD_AVX2 ON) +ENDIF() + +IF (KOKKOS_ARCH_WSM) + ARCH_FLAGS( + Intel -xSSE4.2 + PGI -tp=nehalem + Cray NO-VALUE-SPECIFIED + DEFAULT -msse4.2 + ) + SET(KOKKOS_ARCH_SSE42 ON) +ENDIF() + +IF (KOKKOS_ARCH_SNB OR KOKKOS_ARCH_AMDAVX) + SET(KOKKOS_ARCH_AVX ON) + ARCH_FLAGS( + Intel -mavx + PGI -tp=sandybridge + Cray NO-VALUE-SPECIFIED + DEFAULT -mavx + ) +ENDIF() + +IF (KOKKOS_ARCH_HSW) + SET(KOKKOS_ARCH_AVX2 ON) + ARCH_FLAGS( + Intel -xCORE-AVX2 + PGI -tp=haswell + Cray NO-VALUE-SPECIFIED + DEFAULT -march=core-avx2 -mtune=core-avx2 + ) +ENDIF() + +IF (KOKKOS_ARCH_BDW) + SET(KOKKOS_ARCH_AVX2 ON) + ARCH_FLAGS( + Intel -xCORE-AVX2 + PGI -tp=haswell + Cray NO-VALUE-SPECIFIED + DEFAULT -march=core-avx2 -mtune=core-avx2 -mrtm + ) +ENDIF() + +IF (KOKKOS_ARCH_EPYC) + SET(KOKKOS_ARCH_AMD_AVX2 ON) + ARCH_FLAGS( + Intel -mvax2 + DEFAULT -march=znver1 -mtune=znver1 + ) +ENDIF() + +IF (KOKKOS_ARCH_KNL) + #avx512-mic + SET(KOKKOS_ARCH_AVX512MIC ON) #not a cache variable + ARCH_FLAGS( + Intel -xMIC-AVX512 + PGI NO-VALUE-SPECIFIED + Cray NO-VALUE-SPECIFIED + DEFAULT -march=knl -mtune=knl + ) +ENDIF() + +IF (KOKKOS_ARCH_KNC) + SET(KOKKOS_USE_ISA_KNC ON) + ARCH_FLAGS( + DEFAULT -mmic + ) +ENDIF() + +IF (KOKKOS_ARCH_SKX) + #avx512-xeon + SET(KOKKOS_ARCH_AVX512XEON ON) + ARCH_FLAGS( + Intel -xCORE-AVX512 + PGI NO-VALUE-SPECIFIED + Cray NO-VALUE-SPECIFIED + DEFAULT -march=skylake-avx512 -mtune=skylake-avx512 -mrtm + ) +ENDIF() + +IF (KOKKOS_ARCH_WSM OR KOKKOS_ARCH_SNB OR KOKKOS_ARCH_HSW OR KOKKOS_ARCH_BDW OR KOKKOS_ARCH_KNL OR KOKKOS_ARCH_SKX OR KOKKOS_ARCH_EPYC) + SET(KOKKOS_USE_ISA_X86_64 ON) +ENDIF() + +IF (KOKKOS_ARCH_BDW OR KOKKOS_ARCH_SKX) + SET(KOKKOS_ENABLE_TM ON) #not a cache variable +ENDIF() + +IF (KOKKOS_ARCH_POWER7) + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + DEFAULT -mcpu=power7 -mtune=power7 + ) + SET(KOKKOS_USE_ISA_POWERPCBE ON) +ENDIF() + +IF (KOKKOS_ARCH_POWER8) + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + NVIDIA NO-VALUE-SPECIFIED + DEFAULT -mcpu=power8 -mtune=power8 + ) +ENDIF() + +IF (KOKKOS_ARCH_POWER9) + ARCH_FLAGS( + PGI NO-VALUE-SPECIFIED + NVIDIA NO-VALUE-SPECIFIED + DEFAULT -mcpu=power9 -mtune=power9 + ) +ENDIF() + +IF (KOKKOS_ARCH_POWER8 OR KOKKOS_ARCH_POWER9) + SET(KOKKOS_USE_ISA_POWERPCLE ON) +ENDIF() + +IF (Kokkos_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) + ARCH_FLAGS( + Clang -fcuda-rdc + NVIDIA --relocatable-device-code=true + ) +ENDIF() + + +SET(CUDA_ARCH_ALREADY_SPECIFIED "") +FUNCTION(CHECK_CUDA_ARCH ARCH FLAG) +IF(KOKKOS_ARCH_${ARCH}) + IF(CUDA_ARCH_ALREADY_SPECIFIED) + MESSAGE(FATAL_ERROR "Multiple GPU architectures given! Already have ${CUDA_ARCH_ALREADY_SPECIFIED}, but trying to add ${ARCH}. If you are re-running CMake, try clearing the cache and running again.") + ENDIF() + SET(CUDA_ARCH_ALREADY_SPECIFIED ${ARCH} PARENT_SCOPE) + IF (NOT KOKKOS_ENABLE_CUDA) + MESSAGE(WARNING "Given CUDA arch ${ARCH}, but Kokkos_ENABLE_CUDA is OFF. Option will be ignored.") + UNSET(KOKKOS_ARCH_${ARCH} PARENT_SCOPE) + ELSE() + GLOBAL_APPEND(KOKKOS_CUDA_OPTIONS "${CUDA_ARCH_FLAG}=${FLAG}") + IF(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) + GLOBAL_APPEND(KOKKOS_LINK_OPTIONS "${CUDA_ARCH_FLAG}=${FLAG}") + ENDIF() + ENDIF() +ENDIF() +ENDFUNCTION() + + +CHECK_CUDA_ARCH(KEPLER30 sm_30) +CHECK_CUDA_ARCH(KEPLER32 sm_32) +CHECK_CUDA_ARCH(KEPLER35 sm_35) +CHECK_CUDA_ARCH(KEPLER37 sm_37) +CHECK_CUDA_ARCH(MAXWELL50 sm_50) +CHECK_CUDA_ARCH(MAXWELL52 sm_52) +CHECK_CUDA_ARCH(MAXWELL53 sm_53) +CHECK_CUDA_ARCH(PASCAL60 sm_60) +CHECK_CUDA_ARCH(PASCAL61 sm_61) +CHECK_CUDA_ARCH(VOLTA70 sm_70) +CHECK_CUDA_ARCH(VOLTA72 sm_72) +CHECK_CUDA_ARCH(TURING75 sm_75) + +#CMake verbose is kind of pointless +#Let's just always print things +MESSAGE(STATUS "Execution Spaces:") +IF(KOKKOS_ENABLE_CUDA) + MESSAGE(STATUS " Device Parallel: CUDA") +ELSE() + MESSAGE(STATUS " Device Parallel: NONE") +ENDIF() + +FOREACH (_BACKEND OPENMP PTHREAD HPX) + IF(KOKKOS_ENABLE_${_BACKEND}) + IF(_HOST_PARALLEL) + MESSAGE(FATAL_ERROR "Multiple host parallel execution spaces are not allowed! " + "Trying to enable execution space ${_BACKEND}, " + "but execution space ${_HOST_PARALLEL} is already enabled. " + "Remove the CMakeCache.txt file and re-configure.") + ENDIF() + SET(_HOST_PARALLEL ${_BACKEND}) + ENDIF() +ENDFOREACH() + +IF(NOT _HOST_PARALLEL AND NOT KOKKOS_ENABLE_SERIAL) + MESSAGE(FATAL_ERROR "At least one host execution space must be enabled, " + "but no host parallel execution space was requested " + "and Kokkos_ENABLE_SERIAL=OFF.") +ENDIF() + +IF(NOT _HOST_PARALLEL) + SET(_HOST_PARALLEL "NONE") +ENDIF() +MESSAGE(STATUS " Host Parallel: ${_HOST_PARALLEL}") +UNSET(_HOST_PARALLEL) + +IF(KOKKOS_ENABLE_PTHREAD) + SET(KOKKOS_ENABLE_THREADS ON) +ENDIF() + +IF(KOKKOS_ENABLE_SERIAL) + MESSAGE(STATUS " Host Serial: SERIAL") +ELSE() + MESSAGE(STATUS " Host Serial: NONE") +ENDIF() + +MESSAGE(STATUS "") +MESSAGE(STATUS "Architectures:") +FOREACH(Arch ${KOKKOS_ENABLED_ARCH_LIST}) + MESSAGE(STATUS " ${Arch}") +ENDFOREACH() + diff --git a/lib/kokkos/cmake/kokkos_build.cmake b/lib/kokkos/cmake/kokkos_build.cmake deleted file mode 100644 index f9b995baae..0000000000 --- a/lib/kokkos/cmake/kokkos_build.cmake +++ /dev/null @@ -1,261 +0,0 @@ -############################ Detect if submodule ############################### -# -# With thanks to StackOverflow: -# http://stackoverflow.com/questions/25199677/how-to-detect-if-current-scope-has-a-parent-in-cmake -# -get_directory_property(HAS_PARENT PARENT_DIRECTORY) -if(HAS_PARENT) - message(STATUS "Submodule build") - SET(KOKKOS_HEADER_DIR "include/kokkos") -else() - message(STATUS "Standalone build") - SET(KOKKOS_HEADER_DIR "include") -endif() - -################################ Handle the actual build ####################### - -SET(INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") -SET(INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") -SET(INSTALL_INCLUDE_DIR ${KOKKOS_HEADER_DIR} CACHE PATH - "Installation directory for header files") -IF(WIN32 AND NOT CYGWIN) - SET(DEF_INSTALL_CMAKE_DIR CMake) -ELSE() - SET(DEF_INSTALL_CMAKE_DIR lib/CMake/Kokkos) -ENDIF() - -SET(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH - "Installation directory for CMake files") - -# Make relative paths absolute (needed later on) -FOREACH(p LIB BIN INCLUDE CMAKE) - SET(var INSTALL_${p}_DIR) - IF(NOT IS_ABSOLUTE "${${var}}") - SET(${var} "${CMAKE_INSTALL_PREFIX}/${${var}}") - ENDIF() -ENDFOREACH() - -# set up include-directories -SET (Kokkos_INCLUDE_DIRS - ${Kokkos_SOURCE_DIR}/core/src - ${Kokkos_SOURCE_DIR}/containers/src - ${Kokkos_SOURCE_DIR}/algorithms/src - ${Kokkos_BINARY_DIR} # to find KokkosCore_config.h - ${KOKKOS_INCLUDE_DIRS} -) - -# pass include dirs back to parent scope -if(HAS_PARENT) -SET(Kokkos_INCLUDE_DIRS_RET ${Kokkos_INCLUDE_DIRS} PARENT_SCOPE) -else() -SET(Kokkos_INCLUDE_DIRS_RET ${Kokkos_INCLUDE_DIRS}) -endif() - -INCLUDE_DIRECTORIES(${Kokkos_INCLUDE_DIRS}) - -IF(KOKKOS_SEPARATE_LIBS) - # Sources come from makefile-generated kokkos_generated_settings.cmake file - # Separate libs need to separate the sources - set_kokkos_srcs(KOKKOS_SRC ${KOKKOS_SRC}) - - # kokkoscore - ADD_LIBRARY( - kokkoscore - ${KOKKOS_CORE_SRCS} - ) - - target_compile_options( - kokkoscore - PUBLIC $<$:${KOKKOS_CXX_FLAGS}> - ) - - target_include_directories( - kokkoscore - PUBLIC - ${KOKKOS_TPL_INCLUDE_DIRS} - ) - - foreach(lib IN LISTS KOKKOS_TPL_LIBRARY_NAMES) - if (("${lib}" STREQUAL "cuda") AND (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")) - set(LIB_cuda "-lcuda") - elseif ("${lib}" STREQUAL "hpx") - find_package(HPX REQUIRED) - if(${HPX_FOUND}) - target_link_libraries(kokkoscore PUBLIC ${HPX_LIBRARIES}) - target_link_libraries(kokkoscontainers PUBLIC ${HPX_LIBRARIES}) - target_link_libraries(kokkosalgorithms PUBLIC ${HPX_LIBRARIES}) - target_include_directories(kokkoscore PUBLIC ${HPX_INCLUDE_DIRS}) - target_include_directories(kokkoscontainers PUBLIC ${HPX_INCLUDE_DIRS}) - target_include_directories(kokkosalgorithms PUBLIC ${HPX_INCLUDE_DIRS}) - else() - message(ERROR "HPX not found. Check the value of HPX_DIR (= ${HPX_DIR}) or CMAKE_PREFIX_PATH (= ${CMAKE_PREFIX_PATH}).") - endif() - else() - find_library(LIB_${lib} ${lib} PATHS ${KOKKOS_TPL_LIBRARY_DIRS}) - endif() - target_link_libraries(kokkoscore PUBLIC ${LIB_${lib}}) - endforeach() - - target_link_libraries(kokkoscore PUBLIC "${KOKKOS_LINK_FLAGS}") - - # Install the kokkoscore library - INSTALL (TARGETS kokkoscore - EXPORT KokkosTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin - ) - - # kokkoscontainers - if (DEFINED KOKKOS_CONTAINERS_SRCS) - ADD_LIBRARY( - kokkoscontainers - ${KOKKOS_CONTAINERS_SRCS} - ) - endif() - - TARGET_LINK_LIBRARIES( - kokkoscontainers - kokkoscore - ) - - # Install the kokkocontainers library - INSTALL (TARGETS kokkoscontainers - EXPORT KokkosTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - - # kokkosalgorithms - Build as interface library since no source files. - ADD_LIBRARY( - kokkosalgorithms - INTERFACE - ) - - target_include_directories( - kokkosalgorithms - INTERFACE ${Kokkos_SOURCE_DIR}/algorithms/src - ) - - TARGET_LINK_LIBRARIES( - kokkosalgorithms - INTERFACE kokkoscore - ) - - # Install the kokkoalgorithms library - INSTALL (TARGETS kokkosalgorithms - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - - SET (Kokkos_LIBRARIES_NAMES kokkoscore kokkoscontainers kokkosalgorithms) - -ELSE() - # kokkos - ADD_LIBRARY( - kokkos - ${KOKKOS_CORE_SRCS} - ${KOKKOS_CONTAINERS_SRCS} - ) - - target_compile_options( - kokkos - PUBLIC $<$:${KOKKOS_CXX_FLAGS}> - ) - - target_include_directories( - kokkos - PUBLIC - ${KOKKOS_TPL_INCLUDE_DIRS} - ) - - foreach(lib IN LISTS KOKKOS_TPL_LIBRARY_NAMES) - if (("${lib}" STREQUAL "cuda") AND (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")) - set(LIB_cuda "-lcuda") - elseif ("${lib}" STREQUAL "hpx") - find_package(HPX REQUIRED) - if(${HPX_FOUND}) - target_link_libraries(kokkos PUBLIC ${HPX_LIBRARIES}) - target_include_directories(kokkos PUBLIC ${HPX_INCLUDE_DIRS}) - else() - message(ERROR "HPX not found. Check the value of HPX_DIR (= ${HPX_DIR}) or CMAKE_PREFIX_PATH (= ${CMAKE_PREFIX_PATH}).") - endif() - else() - find_library(LIB_${lib} ${lib} PATHS ${KOKKOS_TPL_LIBRARY_DIRS}) - endif() - target_link_libraries(kokkos PUBLIC ${LIB_${lib}}) - endforeach() - - target_link_libraries(kokkos PUBLIC "${KOKKOS_LINK_FLAGS}") - - # Install the kokkos library - INSTALL (TARGETS kokkos - EXPORT KokkosTargets - ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/lib - RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin) - - - SET (Kokkos_LIBRARIES_NAMES kokkos) - -endif() # KOKKOS_SEPARATE_LIBS - -# Install the kokkos headers -INSTALL (DIRECTORY - EXPORT KokkosTargets - ${Kokkos_SOURCE_DIR}/core/src/ - DESTINATION ${KOKKOS_HEADER_DIR} - FILES_MATCHING PATTERN "*.hpp" -) -INSTALL (DIRECTORY - EXPORT KokkosTargets - ${Kokkos_SOURCE_DIR}/containers/src/ - DESTINATION ${KOKKOS_HEADER_DIR} - FILES_MATCHING PATTERN "*.hpp" -) -INSTALL (DIRECTORY - EXPORT KokkosTargets - ${Kokkos_SOURCE_DIR}/algorithms/src/ - DESTINATION ${KOKKOS_HEADER_DIR} - FILES_MATCHING PATTERN "*.hpp" -) - -INSTALL (FILES - ${Kokkos_BINARY_DIR}/KokkosCore_config.h - DESTINATION ${KOKKOS_HEADER_DIR} -) - -# Add all targets to the build-tree export set -export(TARGETS ${Kokkos_LIBRARIES_NAMES} - FILE "${Kokkos_BINARY_DIR}/KokkosTargets.cmake") - -# Export the package for use from the build-tree -# (this registers the build-tree with a global CMake-registry) -export(PACKAGE Kokkos) - -# Create the KokkosConfig.cmake and KokkosConfigVersion files -file(RELATIVE_PATH REL_INCLUDE_DIR "${INSTALL_CMAKE_DIR}" - "${INSTALL_INCLUDE_DIR}") -# ... for the build tree -set(CONF_INCLUDE_DIRS "${Kokkos_SOURCE_DIR}" "${Kokkos_BINARY_DIR}") -configure_file(${Kokkos_SOURCE_DIR}/cmake/KokkosConfig.cmake.in - "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" @ONLY) -# ... for the install tree -set(CONF_INCLUDE_DIRS "\${Kokkos_CMAKE_DIR}/${REL_INCLUDE_DIR}") -configure_file(${Kokkos_SOURCE_DIR}/cmake/KokkosConfig.cmake.in - "${Kokkos_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/KokkosConfig.cmake" @ONLY) - -# Install the KokkosConfig.cmake and KokkosConfigVersion.cmake -install(FILES - "${Kokkos_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/KokkosConfig.cmake" - DESTINATION "${INSTALL_CMAKE_DIR}") - -#This seems not to do anything? -#message(STATUS "KokkosTargets: " ${KokkosTargets}) -# Install the export set for use with the install-tree -INSTALL(EXPORT KokkosTargets DESTINATION - "${INSTALL_CMAKE_DIR}") - -# build and install pkgconfig file -CONFIGURE_FILE(core/src/kokkos.pc.in kokkos.pc @ONLY) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/kokkos.pc DESTINATION lib/pkgconfig) diff --git a/lib/kokkos/cmake/kokkos_compiler_id.cmake b/lib/kokkos/cmake/kokkos_compiler_id.cmake new file mode 100644 index 0000000000..d239c3b32e --- /dev/null +++ b/lib/kokkos/cmake/kokkos_compiler_id.cmake @@ -0,0 +1,80 @@ +KOKKOS_CFG_DEPENDS(COMPILER_ID NONE) + +SET(KOKKOS_CXX_COMPILER ${CMAKE_CXX_COMPILER}) +SET(KOKKOS_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) +SET(KOKKOS_CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) + +# Check if the compiler is nvcc (which really means nvcc_wrapper). +EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version + COMMAND grep nvcc + COMMAND wc -l + OUTPUT_VARIABLE INTERNAL_HAVE_COMPILER_NVCC + OUTPUT_STRIP_TRAILING_WHITESPACE) + + +STRING(REGEX REPLACE "^ +" "" + INTERNAL_HAVE_COMPILER_NVCC ${INTERNAL_HAVE_COMPILER_NVCC}) + + +IF(INTERNAL_HAVE_COMPILER_NVCC) + # SET the compiler id to nvcc. We use the value used by CMake 3.8. + SET(KOKKOS_CXX_COMPILER_ID NVIDIA CACHE STRING INTERNAL FORCE) + + # SET nvcc's compiler version. + EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version + COMMAND grep release + OUTPUT_VARIABLE INTERNAL_CXX_COMPILER_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+$" + TEMP_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION}) + SET(KOKKOS_CXX_COMPILER_VERSION ${TEMP_CXX_COMPILER_VERSION} CACHE STRING INTERNAL FORCE) +ENDIF() + +IF(KOKKOS_CXX_COMPILER_ID STREQUAL Cray) + + # SET nvcc's compiler version. + EXECUTE_PROCESS(COMMAND ${CMAKE_CXX_COMPILER} --version + OUTPUT_VARIABLE INTERNAL_CXX_COMPILER_VERSION + OUTPUT_STRIP_TRAILING_WHITESPACE) + + STRING(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+$" + TEMP_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION}) + SET(KOKKOS_CXX_COMPILER_VERSION ${TEMP_CXX_COMPILER_VERSION} CACHE STRING INTERNAL FORCE) +ENDIF() + +# Enforce the minimum compilers supported by Kokkos. +SET(KOKKOS_MESSAGE_TEXT "Compiler not supported by Kokkos. Required compiler versions:") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Clang 3.5.2 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n GCC 4.8.4 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Intel 15.0.2 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n NVCC 9.0.69 or higher") +SET(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n PGI 17.1 or higher\n") + +IF(KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 3.5.2) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL GNU) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 4.8.4) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL Intel) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 9.0.69) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() + SET(CMAKE_CXX_EXTENSIONS OFF CACHE BOOL "Kokkos turns off CXX extensions" FORCE) +ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL PGI) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 17.1) + MESSAGE(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") + ENDIF() +ENDIF() + +STRING(REPLACE "." ";" VERSION_LIST ${KOKKOS_CXX_COMPILER_VERSION}) +LIST(GET VERSION_LIST 0 KOKKOS_COMPILER_VERSION_MAJOR) +LIST(GET VERSION_LIST 1 KOKKOS_COMPILER_VERSION_MINOR) +LIST(GET VERSION_LIST 2 KOKKOS_COMPILER_VERSION_PATCH) diff --git a/lib/kokkos/cmake/kokkos_corner_cases.cmake b/lib/kokkos/cmake/kokkos_corner_cases.cmake new file mode 100644 index 0000000000..c03c385faf --- /dev/null +++ b/lib/kokkos/cmake/kokkos_corner_cases.cmake @@ -0,0 +1,35 @@ +IF(KOKKOS_CXX_COMPILER_ID STREQUAL Clang AND KOKKOS_ENABLE_OPENMP) + # The clang "version" doesn't actually tell you what runtimes and tools + # were built into Clang. We should therefore make sure that libomp + # was actually built into Clang. Otherwise the user will get nonsensical + # errors when they try to build. + + #Try compile is the height of CMake nonsense + #I can't just give it compiler and link flags + #I have to hackily pretend that compiler flags are compiler definitions + #and that linker flags are libraries + #also - this is easier to use than CMakeCheckCXXSourceCompiles + TRY_COMPILE(CLANG_HAS_OMP + ${KOKKOS_TOP_BUILD_DIR}/corner_cases + ${KOKKOS_SOURCE_DIR}/cmake/compile_tests/clang_omp.cpp + COMPILE_DEFINITIONS -fopenmp=libomp + LINK_LIBRARIES -fopenmp=libomp + ) + IF (NOT CLANG_HAS_OMP) + UNSET(CLANG_HAS_OMP CACHE) #make sure CMake always re-runs this + MESSAGE(FATAL_ERROR "Clang failed OpenMP check. You have requested -DKokkos_ENABLE_OPENMP=ON, but the Clang compiler does not appear to have been built with OpenMP support") + ENDIF() + UNSET(CLANG_HAS_OMP CACHE) #make sure CMake always re-runs this +ENDIF() + + +IF (KOKKOS_CXX_STANDARD STREQUAL 17) + IF (KOKKOS_CXX_COMPILER_ID STREQUAL GNU AND KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 7) + MESSAGE(FATAL_ERROR "You have requested c++17 support for GCC ${KOKKOS_CXX_COMPILER_VERSION}. Although CMake has allowed this and GCC accepts -std=c++1z/c++17, GCC <= 6 does not properly support *this capture. Please reduce the C++ standard to 14 or upgrade the compiler if you do need 17 support") + ENDIF() + + IF (KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + MESSAGE(FATAL_ERROR "You have requested c++17 support for NVCC. Please reduce the C++ standard to 14. No versions of NVCC currently support 17.") + ENDIF() +ENDIF() + diff --git a/lib/kokkos/cmake/kokkos_enable_devices.cmake b/lib/kokkos/cmake/kokkos_enable_devices.cmake new file mode 100644 index 0000000000..ff09876673 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_enable_devices.cmake @@ -0,0 +1,61 @@ + +FUNCTION(KOKKOS_DEVICE_OPTION SUFFIX DEFAULT DEV_TYPE DOCSTRING) + KOKKOS_OPTION(ENABLE_${SUFFIX} ${DEFAULT} BOOL ${DOCSTRING}) + STRING(TOUPPER ${SUFFIX} UC_NAME) + IF (KOKKOS_ENABLE_${UC_NAME}) + LIST(APPEND KOKKOS_ENABLED_DEVICES ${SUFFIX}) + #I hate that CMake makes me do this + SET(KOKKOS_ENABLED_DEVICES ${KOKKOS_ENABLED_DEVICES} PARENT_SCOPE) + ENDIF() + SET(KOKKOS_ENABLE_${UC_NAME} ${KOKKOS_ENABLE_${UC_NAME}} PARENT_SCOPE) + IF (KOKKOS_ENABLE_${UC_NAME} AND DEV_TYPE STREQUAL "HOST") + SET(KOKKOS_HAS_HOST ON PARENT_SCOPE) + ENDIF() +ENDFUNCTION() + +KOKKOS_CFG_DEPENDS(DEVICES NONE) + +# Put a check in just in case people are using this option +KOKKOS_DEPRECATED_LIST(DEVICES ENABLE) + + +KOKKOS_DEVICE_OPTION(PTHREAD OFF HOST "Whether to build Pthread backend") +IF (KOKKOS_ENABLE_PTHREAD) + #patch the naming here + SET(KOKKOS_ENABLE_THREADS ON) +ENDIF() + +IF(Trilinos_ENABLE_Kokkos AND Trilinos_ENABLE_OpenMP) + SET(OMP_DEFAULT ON) +ELSE() + SET(OMP_DEFAULT OFF) +ENDIF() +KOKKOS_DEVICE_OPTION(OPENMP ${OMP_DEFAULT} HOST "Whether to build OpenMP backend") + +IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_CUDA) + SET(CUDA_DEFAULT ON) +ELSE() + SET(CUDA_DEFAULT OFF) +ENDIF() +KOKKOS_DEVICE_OPTION(CUDA ${CUDA_DEFAULT} DEVICE "Whether to build CUDA backend") + +IF (KOKKOS_ENABLE_CUDA) + GLOBAL_SET(KOKKOS_DONT_ALLOW_EXTENSIONS "CUDA enabled") +ENDIF() + +# We want this to default to OFF for cache reasons, but if no +# host space is given, then activate serial +IF (KOKKOS_HAS_TRILINOS) + #However, Trilinos always wants Serial ON + SET(SERIAL_DEFAULT ON) +ELSEIF (KOKKOS_HAS_HOST) + SET(SERIAL_DEFAULT OFF) +ELSE() + SET(SERIAL_DEFAULT ON) + IF (NOT DEFINED Kokkos_ENABLE_SERIAL) + MESSAGE(STATUS "SERIAL backend is being turned on to ensure there is at least one Host space. To change this, you must enable another host execution space and configure with -DKokkos_ENABLE_SERIAL=OFF or change CMakeCache.txt") + ENDIF() +ENDIF() +KOKKOS_DEVICE_OPTION(SERIAL ${SERIAL_DEFAULT} HOST "Whether to build serial backend") + +KOKKOS_DEVICE_OPTION(HPX OFF HOST "Whether to build HPX backend (experimental)") diff --git a/lib/kokkos/cmake/kokkos_enable_options.cmake b/lib/kokkos/cmake/kokkos_enable_options.cmake new file mode 100644 index 0000000000..c0e49482b6 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_enable_options.cmake @@ -0,0 +1,92 @@ +########################## NOTES ############################################### +# List the options for configuring kokkos using CMake method of doing it. +# These options then get mapped onto KOKKOS_SETTINGS environment variable by +# kokkos_settings.cmake. It is separate to allow other packages to override +# these variables (e.g., TriBITS). + +########################## AVAILABLE OPTIONS ################################### +# Use lists for documentation, verification, and programming convenience + + +FUNCTION(KOKKOS_ENABLE_OPTION SUFFIX DEFAULT DOCSTRING) + KOKKOS_OPTION(ENABLE_${SUFFIX} ${DEFAULT} BOOL ${DOCSTRING}) + STRING(TOUPPER ${SUFFIX} UC_NAME) + IF (KOKKOS_ENABLE_${UC_NAME}) + LIST(APPEND KOKKOS_ENABLED_OPTIONS ${UC_NAME}) + #I hate that CMake makes me do this + SET(KOKKOS_ENABLED_OPTIONS ${KOKKOS_ENABLED_OPTIONS} PARENT_SCOPE) + ENDIF() + SET(KOKKOS_ENABLE_${UC_NAME} ${KOKKOS_ENABLE_${UC_NAME}} PARENT_SCOPE) +ENDFUNCTION() + +# Certain defaults will depend on knowing the enabled devices +KOKKOS_CFG_DEPENDS(OPTIONS DEVICES) + +# Put a check in just in case people are using this option +KOKKOS_DEPRECATED_LIST(OPTIONS ENABLE) + +KOKKOS_ENABLE_OPTION(CUDA_RELOCATABLE_DEVICE_CODE OFF "Whether to enable relocatable device code (RDC) for CUDA") +KOKKOS_ENABLE_OPTION(CUDA_UVM OFF "Whether to use unified memory (UM) for CUDA by default") +KOKKOS_ENABLE_OPTION(CUDA_LDG_INTRINSIC OFF "Whether to use CUDA LDG intrinsics") +KOKKOS_ENABLE_OPTION(HPX_ASYNC_DISPATCH OFF "Whether HPX supports asynchronous dispatch") +KOKKOS_ENABLE_OPTION(TESTS OFF "Whether to build the unit tests") +STRING(TOUPPER "${CMAKE_BUILD_TYPE}" UPPERCASE_CMAKE_BUILD_TYPE) +IF(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL "DEBUG") + KOKKOS_ENABLE_OPTION(DEBUG ON "Whether to activate extra debug features - may increase compile times") + KOKKOS_ENABLE_OPTION(DEBUG_DUALVIEW_MODIFY_CHECK ON "Debug check on dual views") +ELSE() + KOKKOS_ENABLE_OPTION(DEBUG OFF "Whether to activate extra debug features - may increase compile times") + KOKKOS_ENABLE_OPTION(DEBUG_DUALVIEW_MODIFY_CHECK OFF "Debug check on dual views") +ENDIF() +UNSET(_UPPERCASE_CMAKE_BUILD_TYPE) +KOKKOS_ENABLE_OPTION(LARGE_MEM_TESTS OFF "Whether to perform extra large memory tests") +KOKKOS_ENABLE_OPTION(DEBUG_BOUNDS_CHECK OFF "Whether to use bounds checking - will increase runtime") +KOKKOS_ENABLE_OPTION(COMPILER_WARNINGS OFF "Whether to print all compiler warnings") +KOKKOS_ENABLE_OPTION(PROFILING ON "Whether to create bindings for profiling tools") +KOKKOS_ENABLE_OPTION(PROFILING_LOAD_PRINT OFF "Whether to print information about which profiling tools got loaded") +KOKKOS_ENABLE_OPTION(AGGRESSIVE_VECTORIZATION OFF "Whether to aggressively vectorize loops") +KOKKOS_ENABLE_OPTION(DEPRECATED_CODE OFF "Whether to enable deprecated code") + +IF (KOKKOS_ENABLE_CUDA) + SET(KOKKOS_COMPILER_CUDA_VERSION "${KOKKOS_COMPILER_VERSION_MAJOR}${KOKKOS_COMPILER_VERSION_MINOR}") +ENDIF() + +IF (Trilinos_ENABLE_Kokkos AND TPL_ENABLE_CUDA AND DEFINED KOKKOS_COMPILER_CUDA_VERSION AND KOKKOS_COMPILER_CUDA_VERSION GREATER 70) + SET(LAMBDA_DEFAULT ON) +ELSE() + SET(LAMBDA_DEFAULT OFF) +ENDIF() +KOKKOS_ENABLE_OPTION(CUDA_LAMBDA ${LAMBDA_DEFAULT} "Whether to activate experimental lambda features") +IF (Trilinos_ENABLE_Kokkos) + SET(COMPLEX_ALIGN_DEFAULT OFF) +ELSE() + SET(COMPLEX_ALIGN_DEFAULT ON) +ENDIF() +KOKKOS_ENABLE_OPTION(COMPLEX_ALIGN ${COMPLEX_ALIGN_DEFAULT} "Whether to align Kokkos::complex to 2*alignof(RealType)") + +KOKKOS_ENABLE_OPTION(CUDA_CONSTEXPR OFF "Whether to activate experimental relaxed constexpr functions") + +FUNCTION(check_device_specific_options) + CMAKE_PARSE_ARGUMENTS(SOME "" "DEVICE" "OPTIONS" ${ARGN}) + IF(NOT KOKKOS_ENABLE_${SOME_DEVICE}) + FOREACH(OPTION ${SOME_OPTIONS}) + IF(CMAKE_VERSION VERSION_GREATER_EQUAL 3.14) + IF(NOT DEFINED CACHE{Kokkos_ENABLE_${OPTION}} OR NOT DEFINED CACHE{Kokkos_ENABLE_${SOME_DEVICE}}) + MESSAGE(FATAL_ERROR "Internal logic error: option '${OPTION}' or device '${SOME_DEVICE}' not recognized.") + ENDIF() + ENDIF() + IF(KOKKOS_ENABLE_${OPTION}) + MESSAGE(WARNING "Kokkos_ENABLE_${OPTION} is ON but ${SOME_DEVICE} backend is not enabled. Option will be ignored.") + UNSET(KOKKOS_ENABLE_${OPTION} PARENT_SCOPE) + ENDIF() + ENDFOREACH() + ENDIF() +ENDFUNCTION() + +CHECK_DEVICE_SPECIFIC_OPTIONS(DEVICE CUDA OPTIONS CUDA_UVM CUDA_RELOCATABLE_DEVICE_CODE CUDA_LAMBDA CUDA_CONSTEXPR CUDA_LDG_INTRINSIC) +CHECK_DEVICE_SPECIFIC_OPTIONS(DEVICE HPX OPTIONS HPX_ASYNC_DISPATCH) + +# Needed due to change from deprecated name to new header define name +IF (KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION) + SET(KOKKOS_OPT_RANGE_AGGRESSIVE_VECTORIZATION ON) +ENDIF() diff --git a/lib/kokkos/cmake/kokkos_functions.cmake b/lib/kokkos/cmake/kokkos_functions.cmake index 616618753b..3644c48ddd 100644 --- a/lib/kokkos/cmake/kokkos_functions.cmake +++ b/lib/kokkos/cmake/kokkos_functions.cmake @@ -1,345 +1,700 @@ ################################### FUNCTIONS ################################## # List of functions -# set_kokkos_cxx_compiler -# set_kokkos_cxx_standard -# set_kokkos_srcs - -#------------------------------------------------------------------------------- -# function(set_kokkos_cxx_compiler) -# Sets the following compiler variables that are analogous to the CMAKE_* -# versions. We add the ability to detect NVCC (really nvcc_wrapper). -# KOKKOS_CXX_COMPILER -# KOKKOS_CXX_COMPILER_ID -# KOKKOS_CXX_COMPILER_VERSION -# -# Inputs: -# KOKKOS_ENABLE_CUDA -# CMAKE_CXX_COMPILER -# CMAKE_CXX_COMPILER_ID -# CMAKE_CXX_COMPILER_VERSION -# -# Also verifies the compiler version meets the minimum required by Kokkos. -function(set_kokkos_cxx_compiler) - # Since CMake doesn't recognize the nvcc compiler until 3.8, we use our own - # version of the CMake variables and detect nvcc ourselves. Initially set to - # the CMake variable values. - set(INTERNAL_CXX_COMPILER ${CMAKE_CXX_COMPILER}) - set(INTERNAL_CXX_COMPILER_ID ${CMAKE_CXX_COMPILER_ID}) - set(INTERNAL_CXX_COMPILER_VERSION ${CMAKE_CXX_COMPILER_VERSION}) - - # Check if the compiler is nvcc (which really means nvcc_wrapper). - execute_process(COMMAND ${INTERNAL_CXX_COMPILER} --version - COMMAND grep nvcc - COMMAND wc -l - OUTPUT_VARIABLE INTERNAL_HAVE_COMPILER_NVCC - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(REGEX REPLACE "^ +" "" - INTERNAL_HAVE_COMPILER_NVCC ${INTERNAL_HAVE_COMPILER_NVCC}) - - if(INTERNAL_HAVE_COMPILER_NVCC) - # Set the compiler id to nvcc. We use the value used by CMake 3.8. - set(INTERNAL_CXX_COMPILER_ID NVIDIA) - - # Set nvcc's compiler version. - execute_process(COMMAND ${INTERNAL_CXX_COMPILER} --version - COMMAND grep release - OUTPUT_VARIABLE INTERNAL_CXX_COMPILER_VERSION - OUTPUT_STRIP_TRAILING_WHITESPACE) - - string(REGEX MATCH "[0-9]+\\.[0-9]+\\.[0-9]+$" - INTERNAL_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION}) - endif() - - # Enforce the minimum compilers supported by Kokkos. - set(KOKKOS_MESSAGE_TEXT "Compiler not supported by Kokkos. Required compiler versions:") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Clang 3.5.2 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n GCC 4.8.4 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n Intel 15.0.2 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n NVCC 7.0.28 or higher") - set(KOKKOS_MESSAGE_TEXT "${KOKKOS_MESSAGE_TEXT}\n PGI 17.1 or higher\n") - - if(INTERNAL_CXX_COMPILER_ID STREQUAL Clang) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 3.5.2) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL GNU) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 4.8.4) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL Intel) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL NVIDIA) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 7.0.28) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - elseif(INTERNAL_CXX_COMPILER_ID STREQUAL PGI) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 17.1) - message(FATAL_ERROR "${KOKKOS_MESSAGE_TEXT}") - endif() - endif() - - # Enforce that extensions are turned off for nvcc_wrapper. - if(INTERNAL_CXX_COMPILER_ID STREQUAL NVIDIA) - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - message(FATAL_ERROR "NVCC doesn't support C++ extensions. Set CMAKE_CXX_EXTENSIONS to OFF in your CMakeLists.txt.") - endif() - endif() - - if(KOKKOS_ENABLE_CUDA) - # Enforce that the compiler can compile CUDA code. - if(INTERNAL_CXX_COMPILER_ID STREQUAL Clang) - if(INTERNAL_CXX_COMPILER_VERSION VERSION_LESS 4.0.0) - message(FATAL_ERROR "Compiling CUDA code directly with Clang requires version 4.0.0 or higher.") - endif() - elseif(NOT INTERNAL_CXX_COMPILER_ID STREQUAL NVIDIA) - message(FATAL_ERROR "Invalid compiler for CUDA. The compiler must be nvcc_wrapper or Clang, but compiler ID was ${INTERNAL_CXX_COMPILER_ID}") - endif() - endif() - - set(KOKKOS_CXX_COMPILER ${INTERNAL_CXX_COMPILER} PARENT_SCOPE) - set(KOKKOS_CXX_COMPILER_ID ${INTERNAL_CXX_COMPILER_ID} PARENT_SCOPE) - set(KOKKOS_CXX_COMPILER_VERSION ${INTERNAL_CXX_COMPILER_VERSION} PARENT_SCOPE) -endfunction() - -#------------------------------------------------------------------------------- -# function(set_kokkos_cxx_standard) -# Transitively enforces that the appropriate CXX standard compile flags (C++11 -# or above) are added to targets that use the Kokkos library. Compile features -# are used if possible. Otherwise, the appropriate flags are added to -# KOKKOS_CXX_FLAGS. Values set by the user to CMAKE_CXX_STANDARD and -# CMAKE_CXX_EXTENSIONS are honored. -# -# Outputs: -# KOKKOS_CXX11_FEATURES -# KOKKOS_CXX_FLAGS -# -# Inputs: -# KOKKOS_CXX_COMPILER -# KOKKOS_CXX_COMPILER_ID -# KOKKOS_CXX_COMPILER_VERSION -# -function(set_kokkos_cxx_standard) - # The following table lists the versions of CMake that supports CXX_STANDARD - # and the CXX compile features for different compilers. The versions are - # based on CMake documentation, looking at CMake code, and verifying by - # testing with specific CMake versions. - # - # COMPILER CXX_STANDARD Compile Features - # --------------------------------------------------------------- - # Clang 3.1 3.1 - # GNU 3.1 3.2 - # AppleClang 3.2 3.2 - # Intel 3.6 3.6 - # Cray No No - # PGI No No - # XL No No - # - # For compiling CUDA code using nvcc_wrapper, we will use the host compiler's - # flags for turning on C++11. Since for compiler ID and versioning purposes - # CMake recognizes the host compiler when calling nvcc_wrapper, this just - # works. Both NVCC and nvcc_wrapper only recognize '-std=c++11' which means - # that we can only use host compilers for CUDA builds that use those flags. - # It also means that extensions (gnu++11) can't be turned on for CUDA builds. - - # Check if we can use compile features. - if(NOT KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) - if(CMAKE_CXX_COMPILER_ID STREQUAL Clang) - if(NOT CMAKE_VERSION VERSION_LESS 3.1) - set(INTERNAL_USE_COMPILE_FEATURES ON) - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang OR CMAKE_CXX_COMPILER_ID STREQUAL GNU) - if(NOT CMAKE_VERSION VERSION_LESS 3.2) - set(INTERNAL_USE_COMPILE_FEATURES ON) - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Intel) - if(NOT CMAKE_VERSION VERSION_LESS 3.6) - set(INTERNAL_USE_COMPILE_FEATURES ON) - endif() - endif() - endif() - - if(INTERNAL_USE_COMPILE_FEATURES) - # Use the compile features aspect of CMake to transitively cause C++ flags - # to populate to user code. - - # I'm using a hack by requiring features that I know force the lowest version - # of the compilers we want to support. Clang 3.3 and later support all of - # the C++11 standard. With CMake 3.8 and higher, we could switch to using - # cxx_std_11. - set(KOKKOS_CXX11_FEATURES - cxx_nonstatic_member_init # Forces GCC 4.7 or later and Intel 14.0 or later. - PARENT_SCOPE - ) - else() - # CXX compile features are not yet implemented for this combination of - # compiler and version of CMake. - - if(CMAKE_CXX_COMPILER_ID STREQUAL AppleClang) - # Versions of CMAKE before 3.2 don't support CXX_STANDARD or C++ compile - # features for the AppleClang compiler. Set compiler flags transitively - # here such that they trickle down to a call to target_compile_options(). - - # The following two blocks of code were copied from - # /Modules/Compiler/AppleClang-CXX.cmake from CMake 3.7.2 and then - # modified. - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.0) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "-std=gnu++11") - endif() - - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 6.1) - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-std=c++14") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++14") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.1) - # AppleClang 5.0 knows this flag, but does not set a __cplusplus macro - # greater than 201103L. - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-std=c++1y") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-std=gnu++1y") - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Intel) - # Versions of CMAKE before 3.6 don't support CXX_STANDARD or C++ compile - # features for the Intel compiler. Set compiler flags transitively here - # such that they trickle down to a call to target_compile_options(). - - # The following three blocks of code were copied from - # /Modules/Compiler/Intel-CXX.cmake from CMake 3.7.2 and then modified. - if("x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") - set(_std -Qstd) - set(_ext c++) - else() - set(_std -std) - set(_ext gnu++) - endif() - - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.2) - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "${_std}=c++14") - # TODO: There is no gnu++14 value supported; figure out what to do. - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "${_std}=c++14") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 15.0.0) - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "${_std}=c++1y") - # TODO: There is no gnu++14 value supported; figure out what to do. - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "${_std}=c++1y") - endif() - - if(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 13.0) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "${_std}=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "${_std}=${_ext}11") - elseif(NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS 12.1) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "${_std}=c++0x") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "${_std}=${_ext}0x") - endif() - elseif(CMAKE_CXX_COMPILER_ID STREQUAL Cray) - # CMAKE doesn't support CXX_STANDARD or C++ compile features for the Cray - # compiler. Set compiler options transitively here such that they trickle - # down to a call to target_compile_options(). - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "-hstd=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "-hstd=c++11") - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-hstd=c++11") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-hstd=c++11") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL PGI) - # CMAKE doesn't support CXX_STANDARD or C++ compile features for the PGI - # compiler. Set compiler options transitively here such that they trickle - # down to a call to target_compile_options(). - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "--c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "--c++11") - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "--c++11") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "--c++11") - elseif(CMAKE_CXX_COMPILER_ID STREQUAL XL) - # CMAKE doesn't support CXX_STANDARD or C++ compile features for the XL - # compiler. Set compiler options transitively here such that they trickle - # down to a call to target_compile_options(). - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX14_STANDARD_COMPILE_OPTION "-std=c++11") - set(INTERNAL_CXX14_EXTENSION_COMPILE_OPTION "-std=c++11") - else() - # Assume GNU. CMAKE_CXX_STANDARD is handled correctly by CMake 3.1 and - # above for this compiler. If the user explicitly requests a C++ - # standard, CMake takes care of it. If not, transitively require C++11. - if(NOT CMAKE_CXX_STANDARD) - set(INTERNAL_CXX11_STANDARD_COMPILE_OPTION ${CMAKE_CXX11_STANDARD_COMPILE_OPTION}) - set(INTERNAL_CXX11_EXTENSION_COMPILE_OPTION ${CMAKE_CXX11_EXTENSION_COMPILE_OPTION}) - endif() - endif() - - # Set the C++ standard info for Kokkos respecting user set values for - # CMAKE_CXX_STANDARD and CMAKE_CXX_EXTENSIONS. - # Only use cxx extension if explicitly requested - if(CMAKE_CXX_STANDARD EQUAL 14) - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX14_EXTENSION_COMPILE_OPTION}) - else() - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX14_STANDARD_COMPILE_OPTION}) - endif() - elseif(CMAKE_CXX_STANDARD EQUAL 11) - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_EXTENSION_COMPILE_OPTION}) - else() - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_STANDARD_COMPILE_OPTION}) - endif() - else() - # The user didn't explicitly request a standard, transitively require - # C++11 respecting CMAKE_CXX_EXTENSIONS. - if(DEFINED CMAKE_CXX_EXTENSIONS AND CMAKE_CXX_EXTENSIONS STREQUAL ON) - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_EXTENSION_COMPILE_OPTION}) - else() - set(INTERNAL_CXX_FLAGS ${INTERNAL_CXX11_STANDARD_COMPILE_OPTION}) - endif() - endif() - - set(KOKKOS_CXX_FLAGS ${INTERNAL_CXX_FLAGS} PARENT_SCOPE) - endif() -endfunction() - - -#------------------------------------------------------------------------------- -# function(set_kokkos_sources) -# Takes a list of sources for kokkos (e.g., KOKKOS_SRC from Makefile.kokkos and -# put it into kokkos_generated_settings.cmake) and sorts the files into the subpackages or -# separate_libraries. This is core and containers (algorithms is pure header -# files). -# -# Inputs: -# KOKKOS_SRC +# kokkos_option + +# Validate options are given with correct case and define an internal +# upper-case version for use within + # -# Outputs: -# KOKKOS_CORE_SRCS -# KOKKOS_CONTAINERS_SRCS -# -function(set_kokkos_srcs) - set(opts ) # no-value args - set(oneValArgs ) - set(multValArgs KOKKOS_SRC) # e.g., lists - cmake_parse_arguments(IN "${opts}" "${oneValArgs}" "${multValArgs}" ${ARGN}) - - foreach(sfile ${IN_KOKKOS_SRC}) - string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/" "" stripfile "${sfile}") - string(REPLACE "/" ";" striplist "${stripfile}") - list(GET striplist 0 firstdir) - if(${firstdir} STREQUAL "core") - list(APPEND KOKKOS_CORE_SRCS ${sfile}) - else() - list(APPEND KOKKOS_CONTAINERS_SRCS ${sfile}) - endif() - endforeach() - set(KOKKOS_CORE_SRCS ${KOKKOS_CORE_SRCS} PARENT_SCOPE) - set(KOKKOS_CONTAINERS_SRCS ${KOKKOS_CONTAINERS_SRCS} PARENT_SCOPE) - return() -endfunction() - -# Setting a default value if it is not already set -macro(set_kokkos_default_default VARIABLE DEFAULT) - IF( "${KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT}" STREQUAL "" ) - IF( "${KOKKOS_ENABLE_${VARIABLE}}" STREQUAL "" ) - set(KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT ${DEFAULT}) - # MESSAGE(WARNING "Set: KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT to ${KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT}") +# +# @FUNCTION: kokkos_deprecated_list +# +# Function that checks if a deprecated list option like Kokkos_ARCH was given. +# This prints an error and prevents configure from completing. +# It attempts to print a helpful message about updating the options for the new CMake. +# Kokkos_${SUFFIX} is the name of the option (like Kokkos_ARCH) being checked. +# Kokkos_${PREFIX}_X is the name of new option to be defined from a list X,Y,Z,... +FUNCTION(kokkos_deprecated_list SUFFIX PREFIX) + SET(CAMEL_NAME Kokkos_${SUFFIX}) + STRING(TOUPPER ${CAMEL_NAME} UC_NAME) + + #I don't love doing it this way but better to be safe + FOREACH(opt ${KOKKOS_GIVEN_VARIABLES}) + STRING(TOUPPER ${opt} OPT_UC) + IF ("${OPT_UC}" STREQUAL "${UC_NAME}") + STRING(REPLACE "," ";" optlist "${${opt}}") + SET(ERROR_MSG "Given deprecated option list ${opt}. This must now be given as separate -D options, which assuming you spelled options correctly would be:") + FOREACH(entry ${optlist}) + STRING(TOUPPER ${entry} ENTRY_UC) + STRING(APPEND ERROR_MSG "\n -DKokkos_${PREFIX}_${ENTRY_UC}=ON") + ENDFOREACH() + STRING(APPEND ERROR_MSG "\nRemove CMakeCache.txt and re-run. For a list of valid options, refer to BUILD.md or even look at CMakeCache.txt (before deleting it).") + IF (KOKKOS_HAS_TRILINOS) + MESSAGE(WARNING ${ERROR_MSG}) + FOREACH(entry ${optlist}) + STRING(TOUPPER ${entry} ENTRY_UC) + SET(${CAMEL_NAME}_${ENTRY_UC} ON CACHE BOOL "Deprecated Trilinos translation") + ENDFOREACH() + UNSET(${opt} CACHE) + ELSE() + MESSAGE(SEND_ERROR ${ERROR_MSG}) + ENDIF() + ENDIF() + ENDFOREACH() +ENDFUNCTION() + +FUNCTION(kokkos_option CAMEL_SUFFIX DEFAULT TYPE DOCSTRING) + SET(CAMEL_NAME Kokkos_${CAMEL_SUFFIX}) + STRING(TOUPPER ${CAMEL_NAME} UC_NAME) + + # Make sure this appears in the cache with the appropriate DOCSTRING + SET(${CAMEL_NAME} ${DEFAULT} CACHE ${TYPE} ${DOCSTRING}) + + #I don't love doing it this way because it's N^2 in number options, but cest la vie + FOREACH(opt ${KOKKOS_GIVEN_VARIABLES}) + STRING(TOUPPER ${opt} OPT_UC) + IF ("${OPT_UC}" STREQUAL "${UC_NAME}") + IF (NOT "${opt}" STREQUAL "${CAMEL_NAME}") + IF (KOKKOS_HAS_TRILINOS) + #Allow this for now if Trilinos... we need to bootstrap our way to integration + MESSAGE(WARNING "Deprecated option ${opt} found - please change spelling to ${CAMEL_NAME}") + SET(${CAMEL_NAME} "${${opt}}" CACHE ${TYPE} ${DOCSTRING} FORCE) + UNSET(${opt} CACHE) + ELSE() + MESSAGE(FATAL_ERROR "Matching option found for ${CAMEL_NAME} with the wrong case ${opt}. Please delete your CMakeCache.txt and change option to -D${CAMEL_NAME}=${${opt}}. This is now enforced to avoid hard-to-debug CMake cache inconsistencies.") + ENDIF() + ENDIF() + ENDIF() + ENDFOREACH() + + #okay, great, we passed the validation test - use the default + IF (DEFINED ${CAMEL_NAME}) + SET(${UC_NAME} ${${CAMEL_NAME}} PARENT_SCOPE) + ELSE() + SET(${UC_NAME} ${DEFAULT} PARENT_SCOPE) + ENDIF() + +ENDFUNCTION() + +FUNCTION(kokkos_append_config_line LINE) + GLOBAL_APPEND(KOKKOS_TPL_EXPORTS "${LINE}") +ENDFUNCTION() + +MACRO(kokkos_export_cmake_tpl NAME) + #CMake TPLs are located with a call to find_package + #find_package locates XConfig.cmake files through + #X_DIR or X_ROOT variables set prior to calling find_package + + #If Kokkos was configured to find the TPL through a _DIR variable + #make sure thar DIR variable is available to downstream packages + IF (DEFINED ${NAME}_DIR) + #The downstream project may override the TPL location that Kokkos used + #Check if the downstream project chose its own TPL location + #If not, make the Kokkos found location available + KOKKOS_APPEND_CONFIG_LINE("IF(NOT DEFINED ${NAME}_DIR)") + KOKKOS_APPEND_CONFIG_LINE(" SET(${NAME}_DIR ${${NAME}_DIR})") + KOKKOS_APPEND_CONFIG_LINE("ENDIF()") + ENDIF() + + IF (DEFINED ${NAME}_ROOT) + #The downstream project may override the TPL location that Kokkos used + #Check if the downstream project chose its own TPL location + #If not, make the Kokkos found location available + KOKKOS_APPEND_CONFIG_LINE("IF(NOT DEFINED ${NAME}_ROOT)") + KOKKOS_APPEND_CONFIG_LINE(" SET(${NAME}_ROOT ${${NAME}_ROOT})") + KOKKOS_APPEND_CONFIG_LINE("ENDIF()") + ENDIF() + KOKKOS_APPEND_CONFIG_LINE("FIND_DEPENDENCY(${NAME})") +ENDMACRO() + +MACRO(kokkos_export_imported_tpl NAME) + IF (NOT KOKKOS_HAS_TRILINOS) + GET_TARGET_PROPERTY(LIB_TYPE ${NAME} TYPE) + IF (${LIB_TYPE} STREQUAL "INTERFACE_LIBRARY") + # This is not an imported target + # This an interface library that we created + INSTALL( + TARGETS ${NAME} + EXPORT KokkosTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) ELSE() - set(KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT ${KOKKOS_ENABLE_${VARIABLE}}) - # MESSAGE(WARNING "Set: KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT to ${KOKKOS_INTERNAL_ENABLE_${VARIABLE}_DEFAULT}") + #make sure this also gets "exported" in the config file + KOKKOS_APPEND_CONFIG_LINE("IF(NOT TARGET ${NAME})") + KOKKOS_APPEND_CONFIG_LINE("ADD_LIBRARY(${NAME} UNKNOWN IMPORTED)") + KOKKOS_APPEND_CONFIG_LINE("SET_TARGET_PROPERTIES(${NAME} PROPERTIES") + + GET_TARGET_PROPERTY(TPL_LIBRARY ${NAME} IMPORTED_LOCATION) + IF(TPL_LIBRARY) + KOKKOS_APPEND_CONFIG_LINE("IMPORTED_LOCATION ${TPL_LIBRARY}") + ENDIF() + + GET_TARGET_PROPERTY(TPL_INCLUDES ${NAME} INTERFACE_INCLUDE_DIRECTORIES) + IF(TPL_INCLUDES) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_INCLUDE_DIRECTORIES ${TPL_INCLUDES}") + ENDIF() + + GET_TARGET_PROPERTY(TPL_COMPILE_OPTIONS ${NAME} INTERFACE_COMPILE_OPTIONS) + IF(TPL_COMPILE_OPTIONS) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_COMPILE_OPTIONS ${TPL_COMPILE_OPTIONS}") + ENDIF() + + SET(TPL_LINK_OPTIONS) + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13.0") + GET_TARGET_PROPERTY(TPL_LINK_OPTIONS ${NAME} INTERFACE_LINK_OPTIONS) + ENDIF() + IF(TPL_LINK_OPTIONS) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_LINK_OPTIONS ${TPL_LINK_OPTIONS}") + ENDIF() + + GET_TARGET_PROPERTY(TPL_LINK_LIBRARIES ${NAME} INTERFACE_LINK_LIBRARIES) + IF(TPL_LINK_LIBRARIES) + KOKKOS_APPEND_CONFIG_LINE("INTERFACE_LINK_LIBRARIES ${TPL_LINK_LIBRARIES}") + ENDIF() + KOKKOS_APPEND_CONFIG_LINE(")") + KOKKOS_APPEND_CONFIG_LINE("ENDIF()") ENDIF() ENDIF() - UNSET(KOKKOS_ENABLE_${VARIABLE} CACHE) -endmacro() +ENDMACRO() + + +# +# @MACRO: KOKKOS_IMPORT_TPL() +# +# Function that checks if a third-party library (TPL) has been enabled and calls `find_package` +# to create an imported target encapsulating all the flags and libraries +# needed to use the TPL +# +# Usage:: +# +# KOKKOS_IMPORT_TPL( +# +# NO_EXPORT +# INTERFACE +# +# ``NO_EXPORT`` +# +# If specified, this TPL will not be added to KokkosConfig.cmake as an export +# +# ``INTERFACE`` +# +# If specified, this TPL will build an INTERFACE library rather than an +# IMPORTED target +MACRO(kokkos_import_tpl NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "NO_EXPORT;INTERFACE" + "" + "" + ${ARGN}) + IF (TPL_INTERFACE) + SET(TPL_IMPORTED_NAME ${NAME}) + ELSE() + SET(TPL_IMPORTED_NAME Kokkos::${NAME}) + ENDIF() + + # Even though this policy gets set in the top-level CMakeLists.txt, + # I have still been getting errors about ROOT variables being ignored + # I'm not sure if this is a scope issue - but make sure + # the policy is set before we do any find_package calls + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") + CMAKE_POLICY(SET CMP0074 NEW) + ENDIF() + + IF (KOKKOS_ENABLE_${NAME}) + #Tack on a TPL here to make sure we avoid using anyone else's find + FIND_PACKAGE(TPL${NAME} REQUIRED MODULE) + IF(NOT TARGET ${TPL_IMPORTED_NAME}) + MESSAGE(FATAL_ERROR "Find module succeeded for ${NAME}, but did not produce valid target ${TPL_IMPORTED_NAME}") + ENDIF() + IF(NOT TPL_NO_EXPORT) + KOKKOS_EXPORT_IMPORTED_TPL(${TPL_IMPORTED_NAME}) + ENDIF() + LIST(APPEND KOKKOS_ENABLED_TPLS ${NAME}) + ENDIF() +ENDMACRO(kokkos_import_tpl) + +MACRO(kokkos_import_cmake_tpl MODULE_NAME) + kokkos_import_tpl(${MODULE_NAME} ${ARGN} NO_EXPORT) + CMAKE_PARSE_ARGUMENTS(TPL + "NO_EXPORT" + "OPTION_NAME" + "" + ${ARGN}) + + IF (NOT TPL_OPTION_NAME) + SET(TPL_OPTION_NAME ${MODULE_NAME}) + ENDIF() + + IF (NOT TPL_NO_EXPORT) + KOKKOS_EXPORT_CMAKE_TPL(${MODULE_NAME}) + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_CREATE_IMPORTED_TPL() +# +# Function that creates an imported target encapsulating all the flags +# and libraries needed to use the TPL +# +# Usage:: +# +# KOKKOS_CREATE_IMPORTED_TPL( +# +# INTERFACE +# LIBRARY +# LINK_LIBRARIES ... +# COMPILE_OPTIONS ... +# LINK_OPTIONS ... +# +# ``INTERFACE`` +# +# If specified, this TPL will build an INTERFACE library rather than an +# IMPORTED target +# +# ``LIBRARY `` +# +# If specified, this gives the IMPORTED_LOCATION of the library. +# +# ``LINK_LIBRARIES ...`` +# +# If specified, this gives a list of dependent libraries that also +# need to be linked against. Each entry can be a library path or +# the name of a valid CMake target. +# +# ``INCLUDES ...`` +# +# If specified, this gives a list of directories that must be added +# to the include path for using this library. +# +# ``COMPILE_OPTIONS ...`` +# +# If specified, this gives a list of compiler flags that must be used +# for using this library. +# +# ``LINK_OPTIONS ...`` +# +# If specified, this gives a list of linker flags that must be used +# for using this library. +MACRO(kokkos_create_imported_tpl NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "INTERFACE" + "LIBRARY" + "LINK_LIBRARIES;INCLUDES;COMPILE_OPTIONS;LINK_OPTIONS" + ${ARGN}) + + + IF (KOKKOS_HAS_TRILINOS) + #TODO: we need to set a bunch of cache variables here + ELSEIF (TPL_INTERFACE) + ADD_LIBRARY(${NAME} INTERFACE) + #Give this an importy-looking name + ADD_LIBRARY(Kokkos::${NAME} ALIAS ${NAME}) + IF (TPL_LIBRARY) + MESSAGE(SEND_ERROR "TPL Interface library ${NAME} should not have an IMPORTED_LOCATION") + ENDIF() + #Things have to go in quoted in case we have multiple list entries + IF(TPL_LINK_LIBRARIES) + TARGET_LINK_LIBRARIES(${NAME} INTERFACE ${TPL_LINK_LIBRARIES}) + ENDIF() + IF(TPL_INCLUDES) + TARGET_INCLUDE_DIRECTORIES(${NAME} INTERFACE ${TPL_INCLUDES}) + ENDIF() + IF(TPL_COMPILE_OPTIONS) + TARGET_COMPILE_OPTIONS(${NAME} INTERFACE ${TPL_COMPILE_OPTIONS}) + ENDIF() + IF(TPL_LINK_OPTIONS) + TARGET_LINK_LIBRARIES(${NAME} INTERFACE ${TPL_LINK_OPTIONS}) + ENDIF() + ELSE() + ADD_LIBRARY(${NAME} UNKNOWN IMPORTED) + IF(TPL_LIBRARY) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + IMPORTED_LOCATION ${TPL_LIBRARY}) + ENDIF() + #Things have to go in quoted in case we have multiple list entries + IF(TPL_LINK_LIBRARIES) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_LINK_LIBRARIES "${TPL_LINK_LIBRARIES}") + ENDIF() + IF(TPL_INCLUDES) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_INCLUDE_DIRECTORIES "${TPL_INCLUDES}") + ENDIF() + IF(TPL_COMPILE_OPTIONS) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_COMPILE_OPTIONS "${TPL_COMPILE_OPTIONS}") + ENDIF() + IF(TPL_LINK_OPTIONS) + SET_TARGET_PROPERTIES(${NAME} PROPERTIES + INTERFACE_LINK_LIBRARIES "${TPL_LINK_OPTIONS}") + ENDIF() + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_FIND_HEADER +# +# Function that finds a particular header. This searches custom paths +# or default system paths depending on options. In constrast to CMake +# default, custom paths are prioritized over system paths. The searched +# order is: +# 1. _ROOT variable +# 2. Kokkos__DIR variable +# 3. Locations in the PATHS option +# 4. Default system paths, if allowed. +# +# Default system paths are allowed if none of options (1)-(3) are specified +# or if default paths are specifically allowed via ALLOW_SYSTEM_PATH_FALLBACK +# +# Usage:: +# +# KOKKOS_FIND_HEADER( +# +#
    +# +# [ALLOW_SYSTEM_PATH_FALLBACK] +# [PATHS path1 [path2 ...]] +# ) +# +# ```` +# +# The variable to define with the success or failure of the find +# +# ``
    `` +# +# The name of the header to find +# +# ```` +# +# The name of the TPL the header corresponds to +# +# ``[ALLOW_SYSTEM_PATH_FALLBACK]`` +# +# If custom paths are given and the header is not found +# should we be allowed to search default system paths +# or error out if not found in given paths +# +# ``[PATHS path1 [path2 ...]]`` +# +# Custom paths to search for the header +# +MACRO(kokkos_find_header VAR_NAME HEADER TPL_NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "ALLOW_SYSTEM_PATH_FALLBACK" + "" + "PATHS" + ${ARGN}) + + SET(${HEADER}_FOUND FALSE) + SET(HAVE_CUSTOM_PATHS FALSE) + IF(NOT ${HEADER}_FOUND AND DEFINED ${TPL_NAME}_ROOT) + #ONLY look in the root directory + FIND_PATH(${VAR_NAME} ${HEADER} PATHS ${${TPL_NAME}_ROOT}/include NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF(NOT ${HEADER}_FOUND AND DEFINED KOKKOS_${TPL_NAME}_DIR) + #ONLY look in the root directory + FIND_PATH(${VAR_NAME} ${HEADER} PATHS ${KOKKOS_${TPL_NAME}_DIR}/include NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF (NOT ${HEADER}_FOUND AND TPL_PATHS) + #we got custom paths + #ONLY look in these paths and nowhere else + FIND_PATH(${VAR_NAME} ${HEADER} PATHS ${TPL_PATHS} NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF (NOT HAVE_CUSTOM_PATHS OR TPL_ALLOW_SYSTEM_PATH_FALLBACK) + #Now go ahead and look in system paths + IF (NOT ${HEADER}_FOUND) + FIND_PATH(${VAR_NAME} ${HEADER}) + ENDIF() + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_FIND_LIBRARY +# +# Function that find a particular library. This searches custom paths +# or default system paths depending on options. In constrast to CMake +# default, custom paths are prioritized over system paths. The search +# order is: +# 1. _ROOT variable +# 2. Kokkos__DIR variable +# 3. Locations in the PATHS option +# 4. Default system paths, if allowed. +# +# Default system paths are allowed if none of options (1)-(3) are specified +# or if default paths are specifically allowed via ALLOW_SYSTEM_PATH_FALLBACK +# +# Usage:: +# +# KOKKOS_FIND_LIBRARY( +# +#
    +# +# [ALLOW_SYSTEM_PATH_FALLBACK] +# [PATHS path1 [path2 ...]] +# ) +# +# ```` +# +# The variable to define with the success or failure of the find +# +# ```` +# +# The name of the library to find (NOT prefixed with -l) +# +# ```` +# +# The name of the TPL the library corresponds to +# +# ``ALLOW_SYSTEM_PATH_FALLBACK`` +# +# If custom paths are given and the library is not found +# should we be allowed to search default system paths +# or error out if not found in given paths +# +# ``PATHS`` +# +# Custom paths to search for the library +# +MACRO(kokkos_find_library VAR_NAME LIB TPL_NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "ALLOW_SYSTEM_PATH_FALLBACK" + "" + "PATHS" + ${ARGN}) + + SET(${LIB}_FOUND FALSE) + SET(HAVE_CUSTOM_PATHS FALSE) + IF(NOT ${LIB}_FOUND AND DEFINED ${TPL_NAME}_ROOT) + FIND_LIBRARY(${VAR_NAME} ${LIB} PATHS ${${TPL_NAME}_ROOT}/lib ${${TPL_NAME}_ROOT}/lib64 NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF(NOT ${LIB}_FOUND AND DEFINED KOKKOS_${TPL_NAME}_DIR) + #we got root paths, only look in these paths and nowhere else + FIND_LIBRARY(${VAR_NAME} ${LIB} PATHS ${KOKKOS_${TPL_NAME}_DIR}/lib ${KOKKOS_${TPL_NAME}_DIR}/lib64 NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + IF (NOT ${LIB}_FOUND AND TPL_PATHS) + #we got custom paths, only look in these paths and nowhere else + FIND_LIBRARY(${VAR_NAME} ${LIB} PATHS ${TPL_PATHS} NO_DEFAULT_PATH) + SET(HAVE_CUSTOM_PATHS TRUE) + ENDIF() + + + IF (NOT HAVE_CUSTOM_PATHS OR TPL_ALLOW_SYSTEM_PATH_FALLBACK) + IF (NOT ${LIB}_FOUND) + #Now go ahead and look in system paths + FIND_LIBRARY(${VAR_NAME} ${LIB}) + ENDIF() + ENDIF() +ENDMACRO() + +# +# @MACRO: KOKKOS_FIND_IMPORTED +# +# Function that finds all libraries and headers needed for the tpl +# and creates an imported target encapsulating all the flags and libraries +# +# Usage:: +# +# KOKKOS_FIND_IMPORTED( +# +# INTERFACE +# ALLOW_SYSTEM_PATH_FALLBACK +# LIBRARY +# LINK_LIBRARIES ... +# COMPILE_OPTIONS ... +# LINK_OPTIONS ... +# +# ``INTERFACE`` +# +# If specified, this TPL will build an INTERFACE library rather than an +# IMPORTED target +# +# ``ALLOW_SYSTEM_PATH_FALLBACK" +# +# If custom paths are given and the library is not found +# should we be allowed to search default system paths +# or error out if not found in given paths. +# +# ``LIBRARY `` +# +# If specified, this gives the name of the library to look for +# +# ``MODULE_NAME `` +# +# If specified, the name of the enclosing module passed to +# FIND_PACKAGE(). Defaults to TPL${NAME} if not +# given. +# +# ``IMPORTED_NAME `` +# +# If specified, this gives the name of the target to build. +# Defaults to Kokkos:: +# +# ``LIBRARY_PATHS ...`` +# +# If specified, this gives a list of paths to search for the library +# If not given, _ROOT/lib and _ROOT/lib64 will be searched. +# +# ``HEADER_PATHS ...`` +# +# If specified, this gives a list of paths to search for the headers +# If not given, _ROOT/include and _ROOT/include will be searched. +# +# ``HEADERS ...`` +# +# If specified, this gives a list of headers to find for the package +# +# ``LIBRARIES ...`` +# +# If specified, this gives a list of libraries to find for the package +# +MACRO(kokkos_find_imported NAME) + CMAKE_PARSE_ARGUMENTS(TPL + "INTERFACE;ALLOW_SYSTEM_PATH_FALLBACK" + "HEADER;LIBRARY;IMPORTED_NAME;MODULE_NAME" + "HEADER_PATHS;LIBRARY_PATHS;HEADERS;LIBRARIES" + ${ARGN}) + + IF(NOT TPL_MODULE_NAME) + SET(TPL_MODULE_NAME TPL${NAME}) + ENDIF() + + IF (TPL_ALLOW_SYSTEM_PATH_FALLBACK) + SET(ALLOW_PATH_FALLBACK_OPT ALLOW_SYSTEM_PATH_FALLBACK) + ELSE() + SET(ALLOW_PATH_FALLBACK_OPT) + ENDIF() + + IF (NOT TPL_IMPORTED_NAME) + IF (TPL_INTERFACE) + SET(TPL_IMPORTED_NAME ${NAME}) + ELSE() + SET(TPL_IMPORTED_NAME Kokkos::${NAME}) + ENDIF() + ENDIF() + + SET(${NAME}_INCLUDE_DIRS) + IF (TPL_HEADER) + KOKKOS_FIND_HEADER(${NAME}_INCLUDE_DIRS ${TPL_HEADER} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_HEADER_PATHS}) + ENDIF() + + FOREACH(HEADER ${TPL_HEADERS}) + KOKKOS_FIND_HEADER(HEADER_FIND_TEMP ${HEADER} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_HEADER_PATHS}) + IF(HEADER_FIND_TEMP) + LIST(APPEND ${NAME}_INCLUDE_DIRS ${HEADER_FIND_TEMP}) + ENDIF() + ENDFOREACH() + + SET(${NAME}_LIBRARY) + IF(TPL_LIBRARY) + KOKKOS_FIND_LIBRARY(${NAME}_LIBRARY ${TPL_LIBRARY} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_LIBRARY_PATHS}) + ENDIF() + + SET(${NAME}_FOUND_LIBRARIES) + FOREACH(LIB ${TPL_LIBRARIES}) + KOKKOS_FIND_LIBRARY(${LIB}_LOCATION ${LIB} ${NAME} ${ALLOW_PATH_FALLBACK_OPT} PATHS ${TPL_LIBRARY_PATHS}) + IF(${LIB}_LOCATION) + LIST(APPEND ${NAME}_FOUND_LIBRARIES ${${LIB}_LOCATION}) + ELSE() + SET(${NAME}_FOUND_LIBRARIES ${${LIB}_LOCATION}) + BREAK() + ENDIF() + ENDFOREACH() + + INCLUDE(FindPackageHandleStandardArgs) + #Collect all the variables we need to be valid for + #find_package to have succeeded + SET(TPL_VARS_NEEDED) + IF (TPL_LIBRARY) + LIST(APPEND TPL_VARS_NEEDED ${NAME}_LIBRARY) + ENDIF() + IF(TPL_HEADER) + LIST(APPEND TPL_VARS_NEEDED ${NAME}_INCLUDE_DIRS) + ENDIF() + IF(TPL_LIBRARIES) + LIST(APPEND TPL_VARS_NEEDED ${NAME}_FOUND_LIBRARIES) + ENDIF() + FIND_PACKAGE_HANDLE_STANDARD_ARGS(${TPL_MODULE_NAME} REQUIRED_VARS ${TPL_VARS_NEEDED}) + + MARK_AS_ADVANCED(${NAME}_INCLUDE_DIRS ${NAME}_FOUND_LIBRARIES ${NAME}_LIBRARY) + + IF (${TPL_MODULE_NAME}_FOUND) + SET(IMPORT_TYPE) + IF (TPL_INTERFACE) + SET(IMPORT_TYPE "INTERFACE") + ENDIF() + KOKKOS_CREATE_IMPORTED_TPL(${TPL_IMPORTED_NAME} + ${IMPORT_TYPE} + INCLUDES "${${NAME}_INCLUDE_DIRS}" + LIBRARY "${${NAME}_LIBRARY}" + LINK_LIBRARIES "${${NAME}_FOUND_LIBRARIES}") + ENDIF() +ENDMACRO(kokkos_find_imported) + +# +# @MACRO: KOKKOS_LINK_TPL() +# +# Function that checks if a third-party library (TPL) has been enabled and +# calls target_link_libraries on the given target +# +# Usage:: +# +# KOKKOS_LINK_TPL( +# +# PUBLIC +# PRIVATE +# INTERFACE +# IMPORTED_NAME +# +# +# Checks if Kokkos_ENABLE_=ON and if so links the library +# +# ``PUBLIC/PRIVATE/INTERFACE`` +# +# Specifies the linkage mode. One of these arguments should be given. +# This will then invoke target_link_libraries( PUBLIC/PRIVATE/INTERFACE ) +# +# ``IMPORTED_NAME `` +# +# If specified, this gives the exact name of the target to link against +# target_link_libraries( ) +# +FUNCTION(kokkos_link_tpl TARGET) + CMAKE_PARSE_ARGUMENTS(TPL + "PUBLIC;PRIVATE;INTERFACE" + "IMPORTED_NAME" + "" + ${ARGN}) + #the name of the TPL + SET(TPL ${TPL_UNPARSED_ARGUMENTS}) + IF (KOKKOS_HAS_TRILINOS) + #Do nothing, they will have already been linked + ELSE() + IF (NOT TPL_IMPORTED_NAME) + SET(TPL_IMPORTED_NAME Kokkos::${TPL}) + ENDIF() + IF (KOKKOS_ENABLE_${TPL}) + IF (TPL_PUBLIC) + TARGET_LINK_LIBRARIES(${TARGET} PUBLIC ${TPL_IMPORTED_NAME}) + ELSEIF (TPL_PRIVATE) + TARGET_LINK_LIBRARIES(${TARGET} PRIVATE ${TPL_IMPORTED_NAME}) + ELSEIF (TPL_INTERFACE) + TARGET_LINK_LIBRARIES(${TARGET} INTERFACE ${TPL_IMPORTED_NAME}) + ELSE() + TARGET_LINK_LIBRARIES(${TARGET} ${TPL_IMPORTED_NAME}) + ENDIF() + ENDIF() + ENDIF() +ENDFUNCTION() + diff --git a/lib/kokkos/cmake/kokkos_install.cmake b/lib/kokkos/cmake/kokkos_install.cmake new file mode 100644 index 0000000000..1e4a5a2aad --- /dev/null +++ b/lib/kokkos/cmake/kokkos_install.cmake @@ -0,0 +1,42 @@ +IF (NOT KOKKOS_HAS_TRILINOS) + INCLUDE(GNUInstallDirs) + + #Set all the variables needed for KokkosConfig.cmake + GET_PROPERTY(KOKKOS_PROP_LIBS GLOBAL PROPERTY KOKKOS_LIBRARIES_NAMES) + SET(KOKKOS_LIBRARIES ${KOKKOS_PROP_LIBS}) + + INCLUDE(CMakePackageConfigHelpers) + CONFIGURE_PACKAGE_CONFIG_FILE( + cmake/KokkosConfig.cmake.in + "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake) + + INCLUDE(CMakePackageConfigHelpers) + CONFIGURE_PACKAGE_CONFIG_FILE( + cmake/KokkosConfigCommon.cmake.in + "${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_FULL_LIBDIR}/cmake) + + WRITE_BASIC_PACKAGE_VERSION_FILE("${Kokkos_BINARY_DIR}/KokkosConfigVersion.cmake" + VERSION "${Kokkos_VERSION}" + COMPATIBILITY SameMajorVersion) + + # Install the KokkosConfig*.cmake files + install(FILES + "${Kokkos_BINARY_DIR}/KokkosConfig.cmake" + "${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake" + "${Kokkos_BINARY_DIR}/KokkosConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Kokkos) + install(EXPORT KokkosTargets NAMESPACE Kokkos:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Kokkos) +ELSE() + CONFIGURE_FILE(cmake/KokkosConfigCommon.cmake.in ${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake @ONLY) + file(READ ${Kokkos_BINARY_DIR}/KokkosConfigCommon.cmake KOKKOS_CONFIG_COMMON) + file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/KokkosConfig_install.cmake" ${KOKKOS_CONFIG_COMMON}) +ENDIF() + +# build and install pkgconfig file +CONFIGURE_FILE(core/src/kokkos.pc.in kokkos.pc @ONLY) +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/kokkos.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) + +INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/KokkosCore_config.h DESTINATION ${KOKKOS_HEADER_DIR}) + diff --git a/lib/kokkos/cmake/kokkos_options.cmake b/lib/kokkos/cmake/kokkos_options.cmake deleted file mode 100644 index 239301925c..0000000000 --- a/lib/kokkos/cmake/kokkos_options.cmake +++ /dev/null @@ -1,419 +0,0 @@ -########################## NOTES ############################################### -# List the options for configuring kokkos using CMake method of doing it. -# These options then get mapped onto KOKKOS_SETTINGS environment variable by -# kokkos_settings.cmake. It is separate to allow other packages to override -# these variables (e.g., TriBITS). - -########################## AVAILABLE OPTIONS ################################### -# Use lists for documentation, verification, and programming convenience - -# All CMake options of the type KOKKOS_ENABLE_* -set(KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST) -list(APPEND KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST - Serial - OpenMP - Pthread - Qthread - HPX - Cuda - ROCm - HWLOC - MEMKIND - LIBRT - Cuda_Lambda - Cuda_Relocatable_Device_Code - Cuda_UVM - Cuda_LDG_Intrinsic - HPX_ASYNC_DISPATCH - Debug - Debug_DualView_Modify_Check - Debug_Bounds_Check - Compiler_Warnings - Profiling - Profiling_Load_Print - Aggressive_Vectorization - Deprecated_Code - Explicit_Instantiation - ) - -#------------------------------------------------------------------------------- -#------------------------------- Recognize CamelCase Options --------------------------- -#------------------------------------------------------------------------------- - -foreach(opt ${KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST}) - string(TOUPPER ${opt} OPT ) - IF(DEFINED Kokkos_ENABLE_${opt}) - IF(DEFINED KOKKOS_ENABLE_${OPT}) - IF(NOT ("${KOKKOS_ENABLE_${OPT}}" STREQUAL "${Kokkos_ENABLE_${opt}}")) - IF(DEFINED KOKKOS_ENABLE_${OPT}_INTERNAL) - MESSAGE(WARNING "Defined both Kokkos_ENABLE_${opt}=[${Kokkos_ENABLE_${opt}}] and KOKKOS_ENABLE_${OPT}=[${KOKKOS_ENABLE_${OPT}}] and they differ! Could be caused by old CMakeCache Variable. Run CMake again and warning should disappear. If not you are truly setting both variables.") - IF(NOT ("${Kokkos_ENABLE_${opt}}" STREQUAL "${KOKKOS_ENABLE_${OPT}_INTERNAL}")) - UNSET(KOKKOS_ENABLE_${OPT} CACHE) - SET(KOKKOS_ENABLE_${OPT} ${Kokkos_ENABLE_${opt}}) - MESSAGE(WARNING "SET BOTH VARIABLES KOKKOS_ENABLE_${OPT}: ${KOKKOS_ENABLE_${OPT}}") - ELSE() - SET(Kokkos_ENABLE_${opt} ${KOKKOS_ENABLE_${OPT}}) - ENDIF() - ELSE() - MESSAGE(FATAL_ERROR "Defined both Kokkos_ENABLE_${opt}=[${Kokkos_ENABLE_${opt}}] and KOKKOS_ENABLE_${OPT}=[${KOKKOS_ENABLE_${OPT}}] and they differ!") - ENDIF() - ENDIF() - ELSE() - SET(KOKKOS_INTERNAL_ENABLE_${OPT}_DEFAULT ${Kokkos_ENABLE_${opt}}) - ENDIF() - ENDIF() -endforeach() - -IF(DEFINED Kokkos_ARCH) - MESSAGE(FATAL_ERROR "Defined Kokkos_ARCH, use KOKKOS_ARCH instead!") -ENDIF() -IF(DEFINED Kokkos_Arch) - MESSAGE(FATAL_ERROR "Defined Kokkos_Arch, use KOKKOS_ARCH instead!") -ENDIF() - -#------------------------------------------------------------------------------- -# List of possible host architectures. -#------------------------------------------------------------------------------- -set(KOKKOS_ARCH_LIST) -list(APPEND KOKKOS_ARCH_LIST - None # No architecture optimization - AMDAVX # (HOST) AMD chip - EPYC # (HOST) AMD EPYC Zen-Core CPU - ARMv80 # (HOST) ARMv8.0 Compatible CPU - ARMv81 # (HOST) ARMv8.1 Compatible CPU - ARMv8-ThunderX # (HOST) ARMv8 Cavium ThunderX CPU - ARMv8-TX2 # (HOST) ARMv8 Cavium ThunderX2 CPU - WSM # (HOST) Intel Westmere CPU - SNB # (HOST) Intel Sandy/Ivy Bridge CPUs - HSW # (HOST) Intel Haswell CPUs - BDW # (HOST) Intel Broadwell Xeon E-class CPUs - SKX # (HOST) Intel Sky Lake Xeon E-class HPC CPUs (AVX512) - KNC # (HOST) Intel Knights Corner Xeon Phi - KNL # (HOST) Intel Knights Landing Xeon Phi - BGQ # (HOST) IBM Blue Gene Q - Power7 # (HOST) IBM POWER7 CPUs - Power8 # (HOST) IBM POWER8 CPUs - Power9 # (HOST) IBM POWER9 CPUs - Kepler # (GPU) NVIDIA Kepler default (generation CC 3.5) - Kepler30 # (GPU) NVIDIA Kepler generation CC 3.0 - Kepler32 # (GPU) NVIDIA Kepler generation CC 3.2 - Kepler35 # (GPU) NVIDIA Kepler generation CC 3.5 - Kepler37 # (GPU) NVIDIA Kepler generation CC 3.7 - Maxwell # (GPU) NVIDIA Maxwell default (generation CC 5.0) - Maxwell50 # (GPU) NVIDIA Maxwell generation CC 5.0 - Maxwell52 # (GPU) NVIDIA Maxwell generation CC 5.2 - Maxwell53 # (GPU) NVIDIA Maxwell generation CC 5.3 - Pascal60 # (GPU) NVIDIA Pascal generation CC 6.0 - Pascal61 # (GPU) NVIDIA Pascal generation CC 6.1 - Volta70 # (GPU) NVIDIA Volta generation CC 7.0 - Volta72 # (GPU) NVIDIA Volta generation CC 7.2 - Turing75 # (GPU) NVIDIA Turing generation CC 7.5 - ) - -# List of possible device architectures. -# The case and spelling here needs to match Makefile.kokkos -set(KOKKOS_DEVICES_LIST) -# Options: Cuda,ROCm,OpenMP,Pthread,Qthreads,Serial -list(APPEND KOKKOS_DEVICES_LIST - Cuda # NVIDIA GPU -- see below - OpenMP # OpenMP - Pthread # pthread - Qthreads # qthreads - HPX # HPX - Serial # serial - ROCm # Relocatable device code - ) - -# List of possible TPLs for Kokkos -# From Makefile.kokkos: Options: hwloc,librt,experimental_memkind -set(KOKKOS_USE_TPLS_LIST) -if(APPLE) -list(APPEND KOKKOS_USE_TPLS_LIST - HWLOC # hwloc - MEMKIND # experimental_memkind - ) -else() -list(APPEND KOKKOS_USE_TPLS_LIST - HWLOC # hwloc - LIBRT # librt - MEMKIND # experimental_memkind - ) -endif() -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_HWLOC hwloc) -set(KOKKOS_INTERNAL_LIBRT librt) -set(KOKKOS_INTERNAL_MEMKIND experimental_memkind) - -# List of possible Advanced options -set(KOKKOS_OPTIONS_LIST) -list(APPEND KOKKOS_OPTIONS_LIST - AGGRESSIVE_VECTORIZATION - DISABLE_PROFILING - DISABLE_DUALVIEW_MODIFY_CHECK - ENABLE_PROFILE_LOAD_PRINT - ) -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_LDG_INTRINSIC use_ldg) -set(KOKKOS_INTERNAL_UVM librt) -set(KOKKOS_INTERNAL_RELOCATABLE_DEVICE_CODE rdc) - - -#------------------------------------------------------------------------------- -# List of possible Options for CUDA -#------------------------------------------------------------------------------- -# From Makefile.kokkos: Options: use_ldg,force_uvm,rdc -set(KOKKOS_CUDA_OPTIONS_LIST) -list(APPEND KOKKOS_CUDA_OPTIONS_LIST - LDG_INTRINSIC # use_ldg - UVM # force_uvm - RELOCATABLE_DEVICE_CODE # rdc - LAMBDA # enable_lambda - ) - -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_LDG_INTRINSIC use_ldg) -set(KOKKOS_INTERNAL_UVM force_uvm) -set(KOKKOS_INTERNAL_RELOCATABLE_DEVICE_CODE rdc) -set(KOKKOS_INTERNAL_LAMBDA enable_lambda) - - -#------------------------------------------------------------------------------- -# List of possible Options for HPX -#------------------------------------------------------------------------------- -# From Makefile.kokkos: Options: enable_async_dispatch -set(KOKKOS_HPX_OPTIONS_LIST) -list(APPEND KOKKOS_HPX_OPTIONS_LIST - ASYNC_DISPATCH # enable_async_dispatch - ) - -# Map of cmake variables to Makefile variables -set(KOKKOS_INTERNAL_ENABLE_ASYNC_DISPATCH enable_async_dispatch) - - -#------------------------------------------------------------------------------- -#------------------------------- Create doc strings ---------------------------- -#------------------------------------------------------------------------------- - -set(tmpr "\n ") -string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_ARCH_DOCSTR "${KOKKOS_ARCH_LIST}") -set(KOKKOS_INTERNAL_ARCH_DOCSTR "${tmpr}${KOKKOS_INTERNAL_ARCH_DOCSTR}") -# This would be useful, but we use Foo_ENABLE mechanisms -#string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_DEVICES_DOCSTR "${KOKKOS_DEVICES_LIST}") -#string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_USE_TPLS_DOCSTR "${KOKKOS_USE_TPLS_LIST}") -#string(REPLACE ";" ${tmpr} KOKKOS_INTERNAL_CUDA_OPTIONS_DOCSTR "${KOKKOS_CUDA_OPTIONS_LIST}") - -#------------------------------------------------------------------------------- -#------------------------------- GENERAL OPTIONS ------------------------------- -#------------------------------------------------------------------------------- - -# Setting this variable to a value other than "None" can improve host -# performance by turning on architecture specific code. -# NOT SET is used to determine if the option is passed in. It is reset to -# default "None" down below. -set(KOKKOS_ARCH "NOT_SET" CACHE STRING - "Optimize for specific host architecture. Options are: ${KOKKOS_INTERNAL_ARCH_DOCSTR}") - -# Whether to build separate libraries or now -set(KOKKOS_SEPARATE_LIBS OFF CACHE BOOL "OFF = kokkos. ON = kokkoscore, kokkoscontainers, and kokkosalgorithms.") - -# Qthreads options. -set(KOKKOS_QTHREADS_DIR "" CACHE PATH "Location of Qthreads library.") - -# HPX options. -set(KOKKOS_HPX_DIR "" CACHE PATH "Location of HPX library.") - -# Whether to build separate libraries or now -set(KOKKOS_SEPARATE_TESTS OFF CACHE BOOL "Provide unit test targets with finer granularity.") - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_DEVICES -------------------------------- -#------------------------------------------------------------------------------- -# Figure out default settings -IF(Trilinos_ENABLE_Kokkos) - set_kokkos_default_default(SERIAL ON) - set_kokkos_default_default(PTHREAD OFF) - IF(TPL_ENABLE_QTHREAD) - set_kokkos_default_default(QTHREADS ${TPL_ENABLE_QTHREAD}) - ELSE() - set_kokkos_default_default(QTHREADS OFF) - ENDIF() - IF(TPL_ENABLE_HPX) - set_kokkos_default_default(HPX ON) - ELSE() - set_kokkos_default_default(HPX OFF) - ENDIF() - IF(Trilinos_ENABLE_OpenMP) - set_kokkos_default_default(OPENMP ${Trilinos_ENABLE_OpenMP}) - ELSE() - set_kokkos_default_default(OPENMP OFF) - ENDIF() - IF(TPL_ENABLE_CUDA) - set_kokkos_default_default(CUDA ${TPL_ENABLE_CUDA}) - ELSE() - set_kokkos_default_default(CUDA OFF) - ENDIF() - set_kokkos_default_default(ROCM OFF) -ELSE() - set_kokkos_default_default(SERIAL ON) - set_kokkos_default_default(OPENMP OFF) - set_kokkos_default_default(PTHREAD OFF) - set_kokkos_default_default(QTHREAD OFF) - set_kokkos_default_default(HPX OFF) - set_kokkos_default_default(CUDA OFF) - set_kokkos_default_default(ROCM OFF) -ENDIF() - -# Set which Kokkos backend to use. -# These are the actual options that define the settings. -set(KOKKOS_ENABLE_SERIAL ${KOKKOS_INTERNAL_ENABLE_SERIAL_DEFAULT} CACHE BOOL "Whether to enable the Kokkos::Serial device. This device executes \"parallel\" kernels sequentially on a single CPU thread. It is enabled by default. If you disable this device, please enable at least one other CPU device, such as Kokkos::OpenMP or Kokkos::Threads.") -set(KOKKOS_ENABLE_OPENMP ${KOKKOS_INTERNAL_ENABLE_OPENMP_DEFAULT} CACHE BOOL "Enable OpenMP support in Kokkos." FORCE) -set(KOKKOS_ENABLE_PTHREAD ${KOKKOS_INTERNAL_ENABLE_PTHREAD_DEFAULT} CACHE BOOL "Enable Pthread support in Kokkos.") -set(KOKKOS_ENABLE_QTHREADS ${KOKKOS_INTERNAL_ENABLE_QTHREADS_DEFAULT} CACHE BOOL "Enable Qthreads support in Kokkos.") -set(KOKKOS_ENABLE_HPX ${KOKKOS_INTERNAL_ENABLE_HPX_DEFAULT} CACHE BOOL "Enable HPX support in Kokkos.") -set(KOKKOS_ENABLE_CUDA ${KOKKOS_INTERNAL_ENABLE_CUDA_DEFAULT} CACHE BOOL "Enable CUDA support in Kokkos.") -set(KOKKOS_ENABLE_ROCM ${KOKKOS_INTERNAL_ENABLE_ROCM_DEFAULT} CACHE BOOL "Enable ROCm support in Kokkos.") - - - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS DEBUG and PROFILING -------------------- -#------------------------------------------------------------------------------- - -# Debug related options enable compiler warnings - -set_kokkos_default_default(DEBUG OFF) -set(KOKKOS_ENABLE_DEBUG ${KOKKOS_INTERNAL_ENABLE_DEBUG_DEFAULT} CACHE BOOL "Enable Kokkos Debug.") - -# From Makefile.kokkos: Advanced Options: -#compiler_warnings, aggressive_vectorization, disable_profiling, disable_dualview_modify_check, enable_profile_load_print -set_kokkos_default_default(COMPILER_WARNINGS OFF) -set(KOKKOS_ENABLE_COMPILER_WARNINGS ${KOKKOS_INTERNAL_ENABLE_COMPILER_WARNINGS_DEFAULT} CACHE BOOL "Enable compiler warnings.") - -set_kokkos_default_default(DEBUG_DUALVIEW_MODIFY_CHECK OFF) -set(KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK ${KOKKOS_INTERNAL_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK_DEFAULT} CACHE BOOL "Enable dualview modify check.") - -# Enable aggressive vectorization. -set_kokkos_default_default(AGGRESSIVE_VECTORIZATION OFF) -set(KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION ${KOKKOS_INTERNAL_ENABLE_AGGRESSIVE_VECTORIZATION_DEFAULT} CACHE BOOL "Enable aggressive vectorization.") - -# Enable profiling. -set_kokkos_default_default(PROFILING ON) -set(KOKKOS_ENABLE_PROFILING ${KOKKOS_INTERNAL_ENABLE_PROFILING_DEFAULT} CACHE BOOL "Enable profiling.") - -set_kokkos_default_default(PROFILING_LOAD_PRINT OFF) -set(KOKKOS_ENABLE_PROFILING_LOAD_PRINT ${KOKKOS_INTERNAL_ENABLE_PROFILING_LOAD_PRINT_DEFAULT} CACHE BOOL "Enable profile load print.") - -set_kokkos_default_default(DEPRECATED_CODE ON) -set(KOKKOS_ENABLE_DEPRECATED_CODE ${KOKKOS_INTERNAL_ENABLE_DEPRECATED_CODE_DEFAULT} CACHE BOOL "Enable deprecated code.") - -set_kokkos_default_default(EXPLICIT_INSTANTIATION OFF) -set(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION ${KOKKOS_INTERNAL_ENABLE_EXPLICIT_INSTANTIATION_DEFAULT} CACHE BOOL "Enable explicit template instantiation.") - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_USE_TPLS ------------------------------- -#------------------------------------------------------------------------------- -# Enable hwloc library. -# Figure out default: -IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_HWLOC) - set_kokkos_default_default(HWLOC ON) -ELSE() - set_kokkos_default_default(HWLOC OFF) -ENDIF() -set(KOKKOS_ENABLE_HWLOC ${KOKKOS_INTERNAL_ENABLE_HWLOC_DEFAULT} CACHE BOOL "Enable hwloc for better process placement.") -set(KOKKOS_HWLOC_DIR "" CACHE PATH "Location of hwloc library. (kokkos tpl)") - -# Enable memkind library. -set_kokkos_default_default(MEMKIND OFF) -set(KOKKOS_ENABLE_MEMKIND ${KOKKOS_INTERNAL_ENABLE_MEMKIND_DEFAULT} CACHE BOOL "Enable memkind. (kokkos tpl)") -set(KOKKOS_MEMKIND_DIR "" CACHE PATH "Location of memkind library. (kokkos tpl)") - -# Enable rt library. -IF(Trilinos_ENABLE_Kokkos) - IF(DEFINED TPL_ENABLE_LIBRT) - set_kokkos_default_default(LIBRT ${TPL_ENABLE_LIBRT}) - ELSE() - set_kokkos_default_default(LIBRT OFF) - ENDIF() -ELSE() - set_kokkos_default_default(LIBRT ON) -ENDIF() -set(KOKKOS_ENABLE_LIBRT ${KOKKOS_INTERNAL_ENABLE_LIBRT_DEFAULT} CACHE BOOL "Enable librt for more precise timer. (kokkos tpl)") - - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_CUDA_OPTIONS --------------------------- -#------------------------------------------------------------------------------- - -# CUDA options. -# Set Defaults -set_kokkos_default_default(CUDA_LDG_INTRINSIC_DEFAULT OFF) -set_kokkos_default_default(CUDA_UVM_DEFAULT OFF) -set_kokkos_default_default(CUDA_RELOCATABLE_DEVICE_CODE OFF) -IF(Trilinos_ENABLE_Kokkos) - IF(KOKKOS_ENABLE_CUDA) - find_package(CUDA) - ENDIF() - IF (DEFINED CUDA_VERSION) - IF (CUDA_VERSION VERSION_GREATER "7.0") - set_kokkos_default_default(CUDA_LAMBDA ON) - ELSE() - set_kokkos_default_default(CUDA_LAMBDA OFF) - ENDIF() - ENDIF() -ELSE() - set_kokkos_default_default(CUDA_LAMBDA OFF) -ENDIF() - -# Set actual options -set(KOKKOS_CUDA_DIR "" CACHE PATH "Location of CUDA library. Defaults to where nvcc installed.") -set(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ${KOKKOS_INTERNAL_ENABLE_CUDA_LDG_INTRINSIC_DEFAULT} CACHE BOOL "Enable CUDA LDG. (cuda option)") -set(KOKKOS_ENABLE_CUDA_UVM ${KOKKOS_INTERNAL_ENABLE_CUDA_UVM_DEFAULT} CACHE BOOL "Enable CUDA unified virtual memory.") -set(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE ${KOKKOS_INTERNAL_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE_DEFAULT} CACHE BOOL "Enable relocatable device code for CUDA. (cuda option)") -set(KOKKOS_ENABLE_CUDA_LAMBDA ${KOKKOS_INTERNAL_ENABLE_CUDA_LAMBDA_DEFAULT} CACHE BOOL "Enable lambdas for CUDA. (cuda option)") - - -#------------------------------------------------------------------------------- -#------------------------------- KOKKOS_HPX_OPTIONS ---------------------------- -#------------------------------------------------------------------------------- - -# HPX options. -# Set Defaults -set_kokkos_default_default(HPX_ASYNC_DISPATCH OFF) - -# Set actual options -set(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH ${KOKKOS_INTERNAL_ENABLE_HPX_ASYNC_DISPATCH_DEFAULT} CACHE BOOL "Enable HPX async dispatch.") - - -#------------------------------------------------------------------------------- -#----------------------- HOST ARCH AND LEGACY TRIBITS -------------------------- -#------------------------------------------------------------------------------- - -# This defines the previous legacy TriBITS builds. -set(KOKKOS_LEGACY_TRIBITS False) -IF ("${KOKKOS_ARCH}" STREQUAL "NOT_SET") - set(KOKKOS_ARCH "None") - IF(KOKKOS_HAS_TRILINOS) - set(KOKKOS_LEGACY_TRIBITS True) - ENDIF() -ENDIF() -IF (KOKKOS_HAS_TRILINOS) - IF (KOKKOS_LEGACY_TRIBITS) - message(STATUS "Using the legacy tribits build because KOKKOS_ARCH not set") - ELSE() - message(STATUS "NOT using the legacy tribits build because KOKKOS_ARCH *is* set") - ENDIF() -ENDIF() - -#------------------------------------------------------------------------------- -#----------------------- Set CamelCase Options if they are not yet set --------- -#------------------------------------------------------------------------------- - -foreach(opt ${KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST}) - string(TOUPPER ${opt} OPT ) - UNSET(KOKKOS_ENABLE_${OPT}_INTERNAL CACHE) - SET(KOKKOS_ENABLE_${OPT}_INTERNAL ${KOKKOS_ENABLE_${OPT}} CACHE BOOL INTERNAL) - IF(DEFINED KOKKOS_ENABLE_${OPT}) - UNSET(Kokkos_ENABLE_${opt} CACHE) - SET(Kokkos_ENABLE_${opt} ${KOKKOS_ENABLE_${OPT}} CACHE BOOL "CamelCase Compatibility setting for KOKKOS_ENABLE_${OPT}") - ENDIF() -endforeach() diff --git a/lib/kokkos/cmake/kokkos_pick_cxx_std.cmake b/lib/kokkos/cmake/kokkos_pick_cxx_std.cmake new file mode 100644 index 0000000000..cf14948f43 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_pick_cxx_std.cmake @@ -0,0 +1,46 @@ +# From CMake 3.10 documentation + +#This can run at any time +KOKKOS_OPTION(CXX_STANDARD "" STRING "The C++ standard for Kokkos to use: 11, 14, 17, or 20. If empty, this will default to CMAKE_CXX_STANDARD. If both CMAKE_CXX_STANDARD and Kokkos_CXX_STANDARD are empty, this will default to 11") + +# Set CXX standard flags +SET(KOKKOS_ENABLE_CXX11 OFF) +SET(KOKKOS_ENABLE_CXX14 OFF) +SET(KOKKOS_ENABLE_CXX17 OFF) +SET(KOKKOS_ENABLE_CXX20 OFF) +IF (KOKKOS_CXX_STANDARD) + IF (${KOKKOS_CXX_STANDARD} STREQUAL "c++98") + MESSAGE(FATAL_ERROR "Kokkos no longer supports C++98 - minimum C++11") + ELSEIF (${KOKKOS_CXX_STANDARD} STREQUAL "c++11") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++11'. Use '11' instead.") + SET(KOKKOS_CXX_STANDARD "11") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++14") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++14'. Use '14' instead.") + SET(KOKKOS_CXX_STANDARD "14") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++17") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++17'. Use '17' instead.") + SET(KOKKOS_CXX_STANDARD "17") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++1y") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++1y'. Use '1Y' instead.") + SET(KOKKOS_CXX_STANDARD "1Y") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++1z") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++1z'. Use '1Z' instead.") + SET(KOKKOS_CXX_STANDARD "1Z") + ELSEIF(${KOKKOS_CXX_STANDARD} STREQUAL "c++2a") + MESSAGE(WARNING "Deprecated Kokkos C++ standard set as 'c++2a'. Use '2A' instead.") + SET(KOKKOS_CXX_STANDARD "2A") + ENDIF() +ENDIF() + +IF (NOT KOKKOS_CXX_STANDARD AND NOT CMAKE_CXX_STANDARD) + MESSAGE(STATUS "Setting default Kokkos CXX standard to 11") + SET(KOKKOS_CXX_STANDARD "11") +ELSEIF(NOT KOKKOS_CXX_STANDARD) + MESSAGE(STATUS "Setting default Kokkos CXX standard to ${CMAKE_CXX_STANDARD}") + SET(KOKKOS_CXX_STANDARD ${CMAKE_CXX_STANDARD}) +ENDIF() + + + + + diff --git a/lib/kokkos/cmake/kokkos_settings.cmake b/lib/kokkos/cmake/kokkos_settings.cmake deleted file mode 100644 index 2c622d0de9..0000000000 --- a/lib/kokkos/cmake/kokkos_settings.cmake +++ /dev/null @@ -1,259 +0,0 @@ -########################## NOTES ############################################### -# This files goal is to take CMake options found in kokkos_options.cmake but -# possibly set from elsewhere -# (see: trilinos/cmake/ProjectCOmpilerPostConfig.cmake) -# using CMake idioms and map them onto the KOKKOS_SETTINGS variables that gets -# passed to the kokkos makefile configuration: -# make -f ${CMAKE_SOURCE_DIR}/core/src/Makefile ${KOKKOS_SETTINGS} build-makefile-cmake-kokkos -# that generates KokkosCore_config.h and kokkos_generated_settings.cmake -# To understand how to form KOKKOS_SETTINGS, see -# /Makefile.kokkos - -#------------------------------------------------------------------------------- -#------------------------------- GENERAL OPTIONS ------------------------------- -#------------------------------------------------------------------------------- - -# Ensure that KOKKOS_ARCH is in the ARCH_LIST -if (KOKKOS_ARCH MATCHES ",") - message("-- Detected a comma in: KOKKOS_ARCH=`${KOKKOS_ARCH}`") - message("-- Although we prefer KOKKOS_ARCH to be semicolon-delimited, we do allow") - message("-- comma-delimited values for compatibility with scripts (see github.com/trilinos/Trilinos/issues/2330)") - string(REPLACE "," ";" KOKKOS_ARCH "${KOKKOS_ARCH}") - message("-- Commas were changed to semicolons, now KOKKOS_ARCH=`${KOKKOS_ARCH}`") -endif() -foreach(arch ${KOKKOS_ARCH}) - list(FIND KOKKOS_ARCH_LIST ${arch} indx) - if (indx EQUAL -1) - message(FATAL_ERROR "`${arch}` is not an accepted value in KOKKOS_ARCH=`${KOKKOS_ARCH}`." - " Please pick from these choices: ${KOKKOS_INTERNAL_ARCH_DOCSTR}") - endif () -endforeach() - -# KOKKOS_SETTINGS uses KOKKOS_ARCH -string(REPLACE ";" "," KOKKOS_GMAKE_ARCH "${KOKKOS_ARCH}") - -# From Makefile.kokkos: Options: yes,no -if(${KOKKOS_ENABLE_DEBUG}) - set(KOKKOS_GMAKE_DEBUG yes) -else() - set(KOKKOS_GMAKE_DEBUG no) -endif() - -#------------------------------- KOKKOS_DEVICES -------------------------------- -# Can have multiple devices -set(KOKKOS_DEVICESl) -foreach(devopt ${KOKKOS_DEVICES_LIST}) - string(TOUPPER ${devopt} devoptuc) - if (${KOKKOS_ENABLE_${devoptuc}}) - list(APPEND KOKKOS_DEVICESl ${devopt}) - endif () -endforeach() -# List needs to be comma-delmitted -string(REPLACE ";" "," KOKKOS_GMAKE_DEVICES "${KOKKOS_DEVICESl}") - -#------------------------------- KOKKOS_OPTIONS -------------------------------- -# From Makefile.kokkos: Options: aggressive_vectorization,disable_profiling,disable_deprecated_code -#compiler_warnings, aggressive_vectorization, disable_profiling, disable_dualview_modify_check, enable_profile_load_print - -set(KOKKOS_OPTIONSl) -if(${KOKKOS_ENABLE_COMPILER_WARNINGS}) - list(APPEND KOKKOS_OPTIONSl compiler_warnings) -endif() -if(${KOKKOS_ENABLE_AGGRESSIVE_VECTORIZATION}) - list(APPEND KOKKOS_OPTIONSl aggressive_vectorization) -endif() -if(NOT ${KOKKOS_ENABLE_PROFILING}) - list(APPEND KOKKOS_OPTIONSl disable_profiling) -endif() -if(NOT ${KOKKOS_ENABLE_DEPRECATED_CODE}) - list(APPEND KOKKOS_OPTIONSl disable_deprecated_code) -endif() -if(NOT ${KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK}) - list(APPEND KOKKOS_OPTIONSl disable_dualview_modify_check) -endif() -if(${KOKKOS_ENABLE_PROFILING_LOAD_PRINT}) - list(APPEND KOKKOS_OPTIONSl enable_profile_load_print) -endif() -if(${KOKKOS_ENABLE_EXPLICIT_INSTANTIATION}) - list(APPEND KOKKOS_OPTIONSl enable_eti) -endif() -# List needs to be comma-delimitted -string(REPLACE ";" "," KOKKOS_GMAKE_OPTIONS "${KOKKOS_OPTIONSl}") - - -#------------------------------- KOKKOS_USE_TPLS ------------------------------- -# Construct the Makefile options -set(KOKKOS_USE_TPLSl) -foreach(tplopt ${KOKKOS_USE_TPLS_LIST}) - if (${KOKKOS_ENABLE_${tplopt}}) - list(APPEND KOKKOS_USE_TPLSl ${KOKKOS_INTERNAL_${tplopt}}) - endif () -endforeach() -# List needs to be comma-delimitted -string(REPLACE ";" "," KOKKOS_GMAKE_USE_TPLS "${KOKKOS_USE_TPLSl}") - - -#------------------------------- KOKKOS_CUDA_OPTIONS --------------------------- -# Construct the Makefile options -set(KOKKOS_CUDA_OPTIONSl) -foreach(cudaopt ${KOKKOS_CUDA_OPTIONS_LIST}) - if (${KOKKOS_ENABLE_CUDA_${cudaopt}}) - list(APPEND KOKKOS_CUDA_OPTIONSl ${KOKKOS_INTERNAL_${cudaopt}}) - endif () -endforeach() -# List needs to be comma-delmitted -string(REPLACE ";" "," KOKKOS_GMAKE_CUDA_OPTIONS "${KOKKOS_CUDA_OPTIONSl}") - -#------------------------------- PATH VARIABLES -------------------------------- -# Want makefile to use same executables specified which means modifying -# the path so the $(shell ...) commands in the makefile see the right exec -# Also, the Makefile's use FOO_PATH naming scheme for -I/-L construction -#TODO: Makefile.kokkos allows this to be overwritten? ROCM_HCC_PATH - -set(KOKKOS_INTERNAL_PATHS) -set(addpathl) -foreach(kvar IN LISTS KOKKOS_USE_TPLS_LIST ITEMS CUDA QTHREADS) - if(${KOKKOS_ENABLE_${kvar}}) - if(DEFINED KOKKOS_${kvar}_DIR) - set(KOKKOS_INTERNAL_PATHS ${KOKKOS_INTERNAL_PATHS} "${kvar}_PATH=${KOKKOS_${kvar}_DIR}") - if(IS_DIRECTORY ${KOKKOS_${kvar}_DIR}/bin) - list(APPEND addpathl ${KOKKOS_${kvar}_DIR}/bin) - endif() - endif() - endif() -endforeach() -# Path env is : delimitted -string(REPLACE ";" ":" KOKKOS_INTERNAL_ADDTOPATH "${addpathl}") - - -######################### SET KOKKOS_SETTINGS ################################## -# Set the KOKKOS_SETTINGS String -- this is the primary communication with the -# makefile configuration. See Makefile.kokkos - -set(KOKKOS_SETTINGS KOKKOS_CMAKE=yes) -set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_SRC_PATH=${KOKKOS_SRC_PATH}) -set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_PATH=${KOKKOS_PATH}) -set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_INSTALL_PATH=${CMAKE_INSTALL_PREFIX}) - -# Form of KOKKOS_foo=$KOKKOS_foo -foreach(kvar ARCH;DEVICES;DEBUG;OPTIONS;CUDA_OPTIONS;USE_TPLS) - if(DEFINED KOKKOS_GMAKE_${kvar}) - if (NOT "${KOKKOS_GMAKE_${kvar}}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} KOKKOS_${kvar}=${KOKKOS_GMAKE_${kvar}}) - endif() - endif() -endforeach() - -# Form of VAR=VAL -#TODO: Makefile supports MPICH_CXX, OMPI_CXX as well -foreach(ovar CXX;CXXFLAGS;LDFLAGS) - if(DEFINED ${ovar}) - if (NOT "${${ovar}}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} ${ovar}=${${ovar}}) - endif() - endif() -endforeach() - -# Finally, do the paths -if (NOT "${KOKKOS_INTERNAL_PATHS}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} ${KOKKOS_INTERNAL_PATHS}) -endif() -if (NOT "${KOKKOS_INTERNAL_ADDTOPATH}" STREQUAL "") - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} "PATH=${KOKKOS_INTERNAL_ADDTOPATH}:$ENV{PATH}") -endif() - -if (CMAKE_CXX_STANDARD) - if (CMAKE_CXX_STANDARD STREQUAL "98") - message(FATAL_ERROR "Kokkos requires C++11 or newer!") - endif() - set(KOKKOS_CXX_STANDARD "c++${CMAKE_CXX_STANDARD}") - if (CMAKE_CXX_EXTENSIONS) - if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - set(KOKKOS_CXX_STANDARD "gnu++${CMAKE_CXX_STANDARD}") - endif() - endif() - set(KOKKOS_SETTINGS ${KOKKOS_SETTINGS} "KOKKOS_CXX_STANDARD=\"${KOKKOS_CXX_STANDARD}\"") -endif() - -# Final form that gets passed to make -set(KOKKOS_SETTINGS env ${KOKKOS_SETTINGS}) - - -############################ PRINT CONFIGURE STATUS ############################ - -if(KOKKOS_CMAKE_VERBOSE) - message(STATUS "") - message(STATUS "****************** Kokkos Settings ******************") - message(STATUS "Execution Spaces") - - if(KOKKOS_ENABLE_CUDA) - message(STATUS " Device Parallel: Cuda") - else() - message(STATUS " Device Parallel: None") - endif() - - if(KOKKOS_ENABLE_OPENMP) - message(STATUS " Host Parallel: OpenMP") - elseif(KOKKOS_ENABLE_PTHREAD) - message(STATUS " Host Parallel: Pthread") - elseif(KOKKOS_ENABLE_QTHREADS) - message(STATUS " Host Parallel: Qthreads") - elseif(KOKKOS_ENABLE_HPX) - message(STATUS " Host Parallel: HPX") - else() - message(STATUS " Host Parallel: None") - endif() - - if(KOKKOS_ENABLE_SERIAL) - message(STATUS " Host Serial: Serial") - else() - message(STATUS " Host Serial: None") - endif() - - message(STATUS "") - message(STATUS "Architectures:") - message(STATUS " ${KOKKOS_GMAKE_ARCH}") - - message(STATUS "") - message(STATUS "Enabled options") - - if(KOKKOS_SEPARATE_LIBS) - message(STATUS " KOKKOS_SEPARATE_LIBS") - endif() - - foreach(opt IN LISTS KOKKOS_INTERNAL_ENABLE_OPTIONS_LIST) - string(TOUPPER ${opt} OPT) - if (KOKKOS_ENABLE_${OPT}) - message(STATUS " KOKKOS_ENABLE_${OPT}") - endif() - endforeach() - - if(KOKKOS_ENABLE_CUDA) - if(KOKKOS_CUDA_DIR) - message(STATUS " KOKKOS_CUDA_DIR: ${KOKKOS_CUDA_DIR}") - endif() - endif() - - if(KOKKOS_QTHREADS_DIR) - message(STATUS " KOKKOS_QTHREADS_DIR: ${KOKKOS_QTHREADS_DIR}") - endif() - - if(KOKKOS_HWLOC_DIR) - message(STATUS " KOKKOS_HWLOC_DIR: ${KOKKOS_HWLOC_DIR}") - endif() - - if(KOKKOS_MEMKIND_DIR) - message(STATUS " KOKKOS_MEMKIND_DIR: ${KOKKOS_MEMKIND_DIR}") - endif() - - if(KOKKOS_HPX_DIR) - message(STATUS " KOKKOS_HPX_DIR: ${KOKKOS_HPX_DIR}") - endif() - - message(STATUS "") - message(STATUS "Final kokkos settings variable:") - message(STATUS " ${KOKKOS_SETTINGS}") - - message(STATUS "*****************************************************") - message(STATUS "") -endif() diff --git a/lib/kokkos/cmake/kokkos_test_cxx_std.cmake b/lib/kokkos/cmake/kokkos_test_cxx_std.cmake new file mode 100644 index 0000000000..c264517abe --- /dev/null +++ b/lib/kokkos/cmake/kokkos_test_cxx_std.cmake @@ -0,0 +1,144 @@ +KOKKOS_CFG_DEPENDS(CXX_STD COMPILER_ID) + +FUNCTION(kokkos_set_cxx_standard_feature standard) + SET(EXTENSION_NAME CMAKE_CXX${standard}_EXTENSION_COMPILE_OPTION) + SET(STANDARD_NAME CMAKE_CXX${standard}_STANDARD_COMPILE_OPTION) + SET(FEATURE_NAME cxx_std_${standard}) + #CMake's way of telling us that the standard (or extension) + #flags are supported is the extension/standard variables + IF (NOT DEFINED CMAKE_CXX_EXTENSIONS) + IF(KOKKOS_DONT_ALLOW_EXTENSIONS) + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS OFF) + ELSE() + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS ON) + ENDIF() + ELSEIF(CMAKE_CXX_EXTENSIONS) + IF(KOKKOS_DONT_ALLOW_EXTENSIONS) + MESSAGE(FATAL_ERROR "The chosen configuration does not support CXX extensions flags: ${KOKKOS_DONT_ALLOW_EXTENSIONS}. Must set CMAKE_CXX_EXTENSIONS=OFF to continue") + ELSE() + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS ON) + ENDIF() + ELSE() + #For trilinos, we need to make sure downstream projects + GLOBAL_SET(KOKKOS_USE_CXX_EXTENSIONS OFF) + ENDIF() + + IF (KOKKOS_USE_CXX_EXTENSIONS AND ${EXTENSION_NAME}) + MESSAGE(STATUS "Using ${${EXTENSION_NAME}} for C++${standard} extensions as feature") + GLOBAL_SET(KOKKOS_CXX_STANDARD_FEATURE ${FEATURE_NAME}) + ELSEIF(NOT KOKKOS_USE_CXX_EXTENSIONS AND ${STANDARD_NAME}) + MESSAGE(STATUS "Using ${${STANDARD_NAME}} for C++${standard} standard as feature") + GLOBAL_SET(KOKKOS_CXX_STANDARD_FEATURE ${FEATURE_NAME}) + ELSE() + #nope, we can't do anything here + MESSAGE(WARNING "C++${standard} is not supported as a compiler feature. We will choose custom flags for now, but this behavior has been deprecated. Please open an issue at https://github.com/kokkos/kokkos/issues reporting that ${KOKKOS_CXX_COMPILER_ID} ${KOKKOS_CXX_COMPILER_VERSION} failed for ${KOKKOS_CXX_STANDARD}, preferrably including your CMake command.") + GLOBAL_SET(KOKKOS_CXX_STANDARD_FEATURE "") + ENDIF() + + IF(NOT ${FEATURE_NAME} IN_LIST CMAKE_CXX_COMPILE_FEATURES) + MESSAGE(FATAL_ERROR "Compiler ${KOKKOS_CXX_COMPILER_ID} should support ${FEATURE_NAME}, but CMake reports feature not supported") + ENDIF() +ENDFUNCTION() + + +IF (KOKKOS_CXX_STANDARD AND CMAKE_CXX_STANDARD) + #make sure these are consistent + IF (NOT KOKKOS_CXX_STANDARD STREQUAL CMAKE_CXX_STANDARD) + MESSAGE(WARNING "Specified both CMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD} and KOKKOS_CXX_STANDARD=${KOKKOS_CXX_STANDARD}, but they don't match") + SET(CMAKE_CXX_STANDARD ${KOKKOS_CXX_STANDARD} CACHE STRING "C++ standard" FORCE) + ENDIF() +ENDIF() + + +IF (KOKKOS_CXX_STANDARD STREQUAL "11" ) + kokkos_set_cxx_standard_feature(11) + SET(KOKKOS_ENABLE_CXX11 ON) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "11") +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "14") + kokkos_set_cxx_standard_feature(14) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "1Y") + SET(KOKKOS_ENABLE_CXX14 ON) +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "17") + kokkos_set_cxx_standard_feature(17) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "1Z") + SET(KOKKOS_ENABLE_CXX17 ON) +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "20") + kokkos_set_cxx_standard_feature(20) + SET(KOKKOS_CXX_INTERMEDIATE_STANDARD "2A") + SET(KOKKOS_ENABLE_CXX20 ON) +ELSEIF(KOKKOS_CXX_STANDARD STREQUAL "98") + MESSAGE(FATAL_ERROR "Kokkos requires C++11 or newer!") +ELSE() + MESSAGE(FATAL_ERROR "Unknown C++ standard ${KOKKOS_CXX_STANDARD} - must be 11, 14, 17, or 20") +ENDIF() + + + +# Enforce that extensions are turned off for nvcc_wrapper. +# For compiling CUDA code using nvcc_wrapper, we will use the host compiler's +# flags for turning on C++11. Since for compiler ID and versioning purposes +# CMake recognizes the host compiler when calling nvcc_wrapper, this just +# works. Both NVCC and nvcc_wrapper only recognize '-std=c++11' which means +# that we can only use host compilers for CUDA builds that use those flags. +# It also means that extensions (gnu++11) can't be turned on for CUDA builds. + +IF(KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + IF(NOT DEFINED CMAKE_CXX_EXTENSIONS) + SET(CMAKE_CXX_EXTENSIONS OFF) + ELSEIF(CMAKE_CXX_EXTENSIONS) + MESSAGE(FATAL_ERROR "NVCC doesn't support C++ extensions. Set -DCMAKE_CXX_EXTENSIONS=OFF") + ENDIF() +ENDIF() + +IF(KOKKOS_ENABLE_CUDA) + # ENFORCE that the compiler can compile CUDA code. + IF(KOKKOS_CXX_COMPILER_ID STREQUAL Clang) + IF(KOKKOS_CXX_COMPILER_VERSION VERSION_LESS 4.0.0) + MESSAGE(FATAL_ERROR "Compiling CUDA code directly with Clang requires version 4.0.0 or higher.") + ENDIF() + IF(NOT DEFINED CMAKE_CXX_EXTENSIONS) + SET(CMAKE_CXX_EXTENSIONS OFF) + ELSEIF(CMAKE_CXX_EXTENSIONS) + MESSAGE(FATAL_ERROR "Compiling CUDA code with clang doesn't support C++ extensions. Set -DCMAKE_CXX_EXTENSIONS=OFF") + ENDIF() + ELSEIF(NOT KOKKOS_CXX_COMPILER_ID STREQUAL NVIDIA) + MESSAGE(FATAL_ERROR "Invalid compiler for CUDA. The compiler must be nvcc_wrapper or Clang, but compiler ID was ${KOKKOS_CXX_COMPILER_ID}") + ENDIF() +ENDIF() + +IF (NOT KOKKOS_CXX_STANDARD_FEATURE) + #we need to pick the C++ flags ourselves + UNSET(CMAKE_CXX_STANDARD) + UNSET(CMAKE_CXX_STANDARD CACHE) + IF(KOKKOS_CXX_COMPILER_ID STREQUAL Cray) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/cray.cmake) + kokkos_set_cray_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL PGI) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/pgi.cmake) + kokkos_set_pgi_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ELSEIF(KOKKOS_CXX_COMPILER_ID STREQUAL Intel) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/intel.cmake) + kokkos_set_intel_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ELSE() + INCLUDE(${KOKKOS_SRC_PATH}/cmake/gnu.cmake) + kokkos_set_gnu_flags(${KOKKOS_CXX_STANDARD} ${KOKKOS_CXX_INTERMEDIATE_STANDARD}) + ENDIF() + #check that the compiler accepts the C++ standard flag + INCLUDE(CheckCXXCompilerFlag) + IF (DEFINED CXX_STD_FLAGS_ACCEPTED) + UNSET(CXX_STD_FLAGS_ACCEPTED CACHE) + ENDIF() + CHECK_CXX_COMPILER_FLAG(${KOKKOS_CXX_STANDARD_FLAG} CXX_STD_FLAGS_ACCEPTED) + IF (NOT CXX_STD_FLAGS_ACCEPTED) + CHECK_CXX_COMPILER_FLAG(${KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG} CXX_INT_STD_FLAGS_ACCEPTED) + IF (NOT CXX_INT_STD_FLAGS_ACCEPTED) + MESSAGE(FATAL_ERROR "${KOKKOS_CXX_COMPILER_ID} did not accept ${KOKKOS_CXX_STANDARD_FLAG} or ${KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG}. You likely need to reduce the level of the C++ standard from ${KOKKOS_CXX_STANDARD}") + ENDIF() + SET(KOKKOS_CXX_STANDARD_FLAG ${KOKKOS_CXX_INTERMEDIATE_STANDARD_FLAG}) + ENDIF() + MESSAGE(STATUS "Compiler features not supported, but ${KOKKOS_CXX_COMPILER_ID} accepts ${KOKKOS_CXX_STANDARD_FLAG}") +ENDIF() + + + + diff --git a/lib/kokkos/cmake/kokkos_tpls.cmake b/lib/kokkos/cmake/kokkos_tpls.cmake new file mode 100644 index 0000000000..181a497d52 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_tpls.cmake @@ -0,0 +1,47 @@ +KOKKOS_CFG_DEPENDS(TPLS OPTIONS) +KOKKOS_CFG_DEPENDS(TPLS DEVICES) + +FUNCTION(KOKKOS_TPL_OPTION PKG DEFAULT) + KOKKOS_ENABLE_OPTION(${PKG} ${DEFAULT} "Whether to enable the ${PKG} library") + KOKKOS_OPTION(${PKG}_DIR "" PATH "Location of ${PKG} library") + SET(KOKKOS_ENABLE_${PKG} ${KOKKOS_ENABLE_${PKG}} PARENT_SCOPE) + SET(KOKKOS_${PKG}_DIR ${KOKKOS_${PKG}_DIR} PARENT_SCOPE) +ENDFUNCTION() + +KOKKOS_TPL_OPTION(HWLOC Off) +KOKKOS_TPL_OPTION(LIBNUMA Off) +KOKKOS_TPL_OPTION(MEMKIND Off) +KOKKOS_TPL_OPTION(CUDA Off) +KOKKOS_TPL_OPTION(LIBRT Off) +KOKKOS_TPL_OPTION(LIBDL On) + +IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_HPX) +SET(HPX_DEFAULT ON) +ELSE() +SET(HPX_DEFAULT OFF) +ENDIF() +KOKKOS_TPL_OPTION(HPX ${HPX_DEFAULT}) + +IF(Trilinos_ENABLE_Kokkos AND TPL_ENABLE_PTHREAD) +SET(PTHREAD_DEFAULT ON) +ELSE() +SET(PTHREAD_DEFAULT OFF) +ENDIF() +KOKKOS_TPL_OPTION(PTHREAD ${PTHREAD_DEFAULT}) + + +#Make sure we use our local FindKokkosCuda.cmake +KOKKOS_IMPORT_TPL(HPX INTERFACE) +KOKKOS_IMPORT_TPL(CUDA INTERFACE) +KOKKOS_IMPORT_TPL(HWLOC) +KOKKOS_IMPORT_TPL(LIBNUMA) +KOKKOS_IMPORT_TPL(LIBRT) +KOKKOS_IMPORT_TPL(LIBDL) +KOKKOS_IMPORT_TPL(MEMKIND) +KOKKOS_IMPORT_TPL(PTHREAD INTERFACE) + +#Convert list to newlines (which CMake doesn't always like in cache variables) +STRING(REPLACE ";" "\n" KOKKOS_TPL_EXPORT_TEMP "${KOKKOS_TPL_EXPORTS}") +#Convert to a regular variable +UNSET(KOKKOS_TPL_EXPORTS CACHE) +SET(KOKKOS_TPL_EXPORTS ${KOKKOS_TPL_EXPORT_TEMP}) diff --git a/lib/kokkos/cmake/kokkos_tribits.cmake b/lib/kokkos/cmake/kokkos_tribits.cmake new file mode 100644 index 0000000000..d2317d2446 --- /dev/null +++ b/lib/kokkos/cmake/kokkos_tribits.cmake @@ -0,0 +1,392 @@ +#These are tribits wrappers only ever called by Kokkos itself + +INCLUDE(CMakeParseArguments) +INCLUDE(CTest) +INCLUDE(GNUInstallDirs) + +MESSAGE(STATUS "The project name is: ${PROJECT_NAME}") + +#Leave this here for now - but only do for tribits +#This breaks the standalone CMake +IF (KOKKOS_HAS_TRILINOS) + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_OpenMP) + SET(${PROJECT_NAME}_ENABLE_OpenMP OFF) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_HPX) + SET(${PROJECT_NAME}_ENABLE_HPX OFF) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_DEBUG) + SET(${PROJECT_NAME}_ENABLE_DEBUG OFF) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_CXX11) + SET(${PROJECT_NAME}_ENABLE_CXX11 ON) + ENDIF() + + IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_TESTS) + SET(${PROJECT_NAME}_ENABLE_TESTS OFF) + ENDIF() + + IF(NOT DEFINED TPL_ENABLE_Pthread) + SET(TPL_ENABLE_Pthread OFF) + ENDIF() +ENDIF() + +MACRO(KOKKOS_SUBPACKAGE NAME) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_SUBPACKAGE(${NAME}) + else() + SET(PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + SET(PARENT_PACKAGE_NAME ${PACKAGE_NAME}) + SET(PACKAGE_NAME ${PACKAGE_NAME}${NAME}) + STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) + SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + endif() +ENDMACRO() + +MACRO(KOKKOS_SUBPACKAGE_POSTPROCESS) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_SUBPACKAGE_POSTPROCESS() + endif() +ENDMACRO() + +MACRO(KOKKOS_PACKAGE_DECL) + + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PACKAGE_DECL(Kokkos) + else() + SET(PACKAGE_NAME Kokkos) + SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) + endif() + + #SET(TRIBITS_DEPS_DIR "${CMAKE_SOURCE_DIR}/cmake/deps") + #FILE(GLOB TPLS_FILES "${TRIBITS_DEPS_DIR}/*.cmake") + #FOREACH(TPL_FILE ${TPLS_FILES}) + # TRIBITS_PROCESS_TPL_DEP_FILE(${TPL_FILE}) + #ENDFOREACH() + +ENDMACRO() + + +MACRO(KOKKOS_PROCESS_SUBPACKAGES) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PROCESS_SUBPACKAGES() + else() + ADD_SUBDIRECTORY(core) + ADD_SUBDIRECTORY(containers) + ADD_SUBDIRECTORY(algorithms) + ADD_SUBDIRECTORY(example) + endif() +ENDMACRO() + +MACRO(KOKKOS_PACKAGE_DEF) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PACKAGE_DEF() + else() + #do nothing + endif() +ENDMACRO() + +MACRO(KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL LIBRARY_NAME) + KOKKOS_LIB_TYPE(${LIBRARY_NAME} INCTYPE) + TARGET_INCLUDE_DIRECTORIES(${LIBRARY_NAME} ${INCTYPE} $) + + INSTALL( + TARGETS ${LIBRARY_NAME} + EXPORT ${PROJECT_NAME} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT ${PACKAGE_NAME} + ) + + INSTALL( + TARGETS ${LIBRARY_NAME} + EXPORT KokkosTargets + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + + VERIFY_EMPTY(KOKKOS_ADD_LIBRARY ${PARSE_UNPARSED_ARGUMENTS}) +ENDMACRO() + +FUNCTION(KOKKOS_ADD_EXECUTABLE EXE_NAME) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_EXECUTABLE(${EXE_NAME} ${ARGN}) + else() + CMAKE_PARSE_ARGUMENTS(PARSE + "TESTONLY" + "" + "SOURCES;TESTONLYLIBS" + ${ARGN}) + + ADD_EXECUTABLE(${EXE_NAME} ${PARSE_SOURCES}) + IF (PARSE_TESTONLYLIBS) + TARGET_LINK_LIBRARIES(${EXE_NAME} ${PARSE_TESTONLYLIBS}) + ENDIF() + VERIFY_EMPTY(KOKKOS_ADD_EXECUTABLE ${PARSE_UNPARSED_ARGUMENTS}) + endif() +ENDFUNCTION() + +IF(NOT TARGET check) + ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) +ENDIF() + + +FUNCTION(KOKKOS_ADD_EXECUTABLE_AND_TEST ROOT_NAME) +IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_EXECUTABLE_AND_TEST( + ${ROOT_NAME} + TESTONLYLIBS kokkos_gtest + ${ARGN} + NUM_MPI_PROCS 1 + COMM serial mpi + FAIL_REGULAR_EXPRESSION " FAILED " + ) +ELSE() + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "SOURCES;CATEGORIES" + ${ARGN}) + VERIFY_EMPTY(KOKKOS_ADD_EXECUTABLE_AND_TEST ${PARSE_UNPARSED_ARGUMENTS}) + SET(EXE_NAME ${PACKAGE_NAME}_${ROOT_NAME}) + KOKKOS_ADD_TEST_EXECUTABLE(${EXE_NAME} + SOURCES ${PARSE_SOURCES} + ) + KOKKOS_ADD_TEST(NAME ${ROOT_NAME} + EXE ${EXE_NAME} + FAIL_REGULAR_EXPRESSION " FAILED " + ) +ENDIF() +ENDFUNCTION() + +MACRO(KOKKOS_SETUP_BUILD_ENVIRONMENT) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_compiler_id.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_enable_devices.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_enable_options.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_test_cxx_std.cmake) + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_arch.cmake) + IF (NOT KOKKOS_HAS_TRILINOS) + SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${Kokkos_SOURCE_DIR}/cmake/Modules/") + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_tpls.cmake) + ENDIF() + INCLUDE(${KOKKOS_SRC_PATH}/cmake/kokkos_corner_cases.cmake) +ENDMACRO() + +MACRO(KOKKOS_ADD_TEST_EXECUTABLE EXE_NAME) + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "SOURCES" + ${ARGN}) + KOKKOS_ADD_EXECUTABLE(${EXE_NAME} + SOURCES ${PARSE_SOURCES} + ${PARSE_UNPARSED_ARGUMENTS} + TESTONLYLIBS kokkos_gtest + ) + IF (NOT KOKKOS_HAS_TRILINOS) + ADD_DEPENDENCIES(check ${EXE_NAME}) + ENDIF() +ENDMACRO() + +MACRO(KOKKOS_PACKAGE_POSTPROCESS) + if (KOKKOS_HAS_TRILINOS) + TRIBITS_PACKAGE_POSTPROCESS() + endif() +ENDMACRO() + +FUNCTION(KOKKOS_SET_LIBRARY_PROPERTIES LIBRARY_NAME) + CMAKE_PARSE_ARGUMENTS(PARSE + "PLAIN_STYLE" + "" + "" + ${ARGN}) + + IF(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.13") + #great, this works the "right" way + TARGET_LINK_OPTIONS( + ${LIBRARY_NAME} PUBLIC ${KOKKOS_LINK_OPTIONS} + ) + ELSE() + IF (PARSE_PLAIN_STYLE) + TARGET_LINK_LIBRARIES( + ${LIBRARY_NAME} ${KOKKOS_LINK_OPTIONS} + ) + ELSE() + #well, have to do it the wrong way for now + TARGET_LINK_LIBRARIES( + ${LIBRARY_NAME} PUBLIC ${KOKKOS_LINK_OPTIONS} + ) + ENDIF() + ENDIF() + + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} PUBLIC + $<$:${KOKKOS_COMPILE_OPTIONS}> + ) + + IF (KOKKOS_ENABLE_CUDA) + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} + PUBLIC $<$:${KOKKOS_CUDA_OPTIONS}> + ) + SET(NODEDUP_CUDAFE_OPTIONS) + FOREACH(OPT ${KOKKOS_CUDAFE_OPTIONS}) + LIST(APPEND NODEDUP_CUDAFE_OPTIONS -Xcudafe ${OPT}) + ENDFOREACH() + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} + PUBLIC $<$:${NODEDUP_CUDAFE_OPTIONS}> + ) + ENDIF() + + LIST(LENGTH KOKKOS_XCOMPILER_OPTIONS XOPT_LENGTH) + IF (XOPT_LENGTH GREATER 1) + MESSAGE(FATAL_ERROR "CMake deduplication does not allow multiple -Xcompiler flags (${KOKKOS_XCOMPILER_OPTIONS}): will require Kokkos to upgrade to minimum 3.12") + ENDIF() + IF(KOKKOS_XCOMPILER_OPTIONS) + SET(NODEDUP_XCOMPILER_OPTIONS) + FOREACH(OPT ${KOKKOS_XCOMPILER_OPTIONS}) + #I have to do this for now because we can't guarantee 3.12 support + #I really should do this with the shell option + LIST(APPEND NODEDUP_XCOMPILER_OPTIONS -Xcompiler) + LIST(APPEND NODEDUP_XCOMPILER_OPTIONS ${OPT}) + ENDFOREACH() + TARGET_COMPILE_OPTIONS( + ${LIBRARY_NAME} + PUBLIC $<$:${NODEDUP_XCOMPILER_OPTIONS}> + ) + ENDIF() + + IF (KOKKOS_CXX_STANDARD_FEATURE) + #GREAT! I can do this the right way + TARGET_COMPILE_FEATURES(${LIBRARY_NAME} PUBLIC ${KOKKOS_CXX_STANDARD_FEATURE}) + IF (NOT KOKKOS_USE_CXX_EXTENSIONS) + SET_TARGET_PROPERTIES(${LIBRARY_NAME} PROPERTIES CXX_EXTENSIONS OFF) + ENDIF() + ELSE() + #OH, well, no choice but the wrong way + TARGET_COMPILE_OPTIONS(${LIBRARY_NAME} PUBLIC ${KOKKOS_CXX_STANDARD_FLAG}) + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_INTERNAL_ADD_LIBRARY LIBRARY_NAME) + CMAKE_PARSE_ARGUMENTS(PARSE + "STATIC;SHARED" + "" + "HEADERS;SOURCES" + ${ARGN}) + + IF(PARSE_HEADERS) + LIST(REMOVE_DUPLICATES PARSE_HEADERS) + ENDIF() + IF(PARSE_SOURCES) + LIST(REMOVE_DUPLICATES PARSE_SOURCES) + ENDIF() + + ADD_LIBRARY( + ${LIBRARY_NAME} + ${PARSE_HEADERS} + ${PARSE_SOURCES} + ) + + KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL(${LIBRARY_NAME}) + + INSTALL( + FILES ${PARSE_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT ${PACKAGE_NAME} + ) + + #In case we are building in-tree, add an alias name + #that matches the install Kokkos:: name + ADD_LIBRARY(Kokkos::${LIBRARY_NAME} ALIAS ${LIBRARY_NAME}) +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_LIBRARY LIBRARY_NAME) + IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_LIBRARY(${LIBRARY_NAME} ${ARGN}) + #Stolen from Tribits - it can add prefixes + SET(TRIBITS_LIBRARY_NAME_PREFIX "${${PROJECT_NAME}_LIBRARY_NAME_PREFIX}") + SET(TRIBITS_LIBRARY_NAME ${TRIBITS_LIBRARY_NAME_PREFIX}${LIBRARY_NAME}) + #Tribits has way too much techinical debt and baggage to even + #allow PUBLIC target_compile_options to be used. It forces C++ flags on projects + #as a giant blob of space-separated strings. We end up with duplicated + #flags between the flags implicitly forced on Kokkos-dependent and those Kokkos + #has in its public INTERFACE_COMPILE_OPTIONS. + #These do NOT get de-deduplicated because Tribits + #creates flags as a giant monolithic space-separated string + #Do not set any transitive properties and keep everything working as before + #KOKKOS_SET_LIBRARY_PROPERTIES(${TRIBITS_LIBRARY_NAME} PLAIN_STYLE) + ELSE() + KOKKOS_INTERNAL_ADD_LIBRARY( + ${LIBRARY_NAME} ${ARGN}) + KOKKOS_SET_LIBRARY_PROPERTIES(${LIBRARY_NAME}) + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_ADD_INTERFACE_LIBRARY NAME) +IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_LIBRARY(${NAME} ${ARGN}) +ELSE() + CMAKE_PARSE_ARGUMENTS(PARSE + "" + "" + "HEADERS;SOURCES" + ${ARGN} + ) + + ADD_LIBRARY(${NAME} INTERFACE) + KOKKOS_INTERNAL_ADD_LIBRARY_INSTALL(${NAME}) + + INSTALL( + FILES ${PARSE_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + ) + + INSTALL( + FILES ${PARSE_HEADERS} + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR} + COMPONENT ${PACKAGE_NAME} + ) +ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_LIB_INCLUDE_DIRECTORIES TARGET) + IF(KOKKOS_HAS_TRILINOS) + #ignore the target, tribits doesn't do anything directly with targets + TRIBITS_INCLUDE_DIRECTORIES(${ARGN}) + ELSE() #append to a list for later + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + FOREACH(DIR ${ARGN}) + TARGET_INCLUDE_DIRECTORIES(${TARGET} ${INCTYPE} $) + ENDFOREACH() + ENDIF() +ENDFUNCTION() + +FUNCTION(KOKKOS_LIB_COMPILE_OPTIONS TARGET) + IF(KOKKOS_HAS_TRILINOS) + #don't trust tribits to do this correctly + KOKKOS_TARGET_COMPILE_OPTIONS(${TARGET} ${ARGN}) + ELSE() + KOKKOS_LIB_TYPE(${TARGET} INCTYPE) + KOKKOS_TARGET_COMPILE_OPTIONS(${${PROJECT_NAME}_LIBRARY_NAME_PREFIX}${TARGET} ${INCTYPE} ${ARGN}) + ENDIF() +ENDFUNCTION() + +MACRO(KOKKOS_ADD_TEST_DIRECTORIES) + IF (KOKKOS_HAS_TRILINOS) + TRIBITS_ADD_TEST_DIRECTORIES(${ARGN}) + ELSE() + IF(KOKKOS_ENABLE_TESTS) + FOREACH(TEST_DIR ${ARGN}) + ADD_SUBDIRECTORY(${TEST_DIR}) + ENDFOREACH() + ENDIF() + ENDIF() +ENDMACRO() diff --git a/lib/kokkos/cmake/pgi.cmake b/lib/kokkos/cmake/pgi.cmake new file mode 100644 index 0000000000..e98e849558 --- /dev/null +++ b/lib/kokkos/cmake/pgi.cmake @@ -0,0 +1,8 @@ + +function(kokkos_set_pgi_flags full_standard int_standard) + STRING(TOLOWER ${full_standard} FULL_LC_STANDARD) + STRING(TOLOWER ${int_standard} INT_LC_STANDARD) + SET(KOKKOS_CXX_STANDARD_FLAG "--c++${FULL_LC_STANDARD}" PARENT_SCOPE) + SET(KOKKOS_CXX_INTERMDIATE_STANDARD_FLAG "--c++${INT_LC_STANDARD}" PARENT_SCOPE) +endfunction() + diff --git a/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake b/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake index aad1e2bad7..b8cee04804 100644 --- a/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake +++ b/lib/kokkos/cmake/tpls/FindTPLCUSPARSE.cmake @@ -67,7 +67,7 @@ ELSE() IF(CUDA_cusparse_LIBRARY STREQUAL "CUDA_cusparse_LIBRARY-NOTFOUND") MESSAGE(FATAL_ERROR "\nCUSPARSE: could not find cuspasre library.") ENDIF() - ENDIF(CMAKE_VERSION VERSION_LESS "2.8.8") + ENDIF() GLOBAL_SET(TPL_CUSPARSE_LIBRARY_DIRS) GLOBAL_SET(TPL_CUSPARSE_INCLUDE_DIRS ${TPL_CUDA_INCLUDE_DIRS}) GLOBAL_SET(TPL_CUSPARSE_LIBRARIES ${CUDA_cusparse_LIBRARY}) diff --git a/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake b/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake index 715b3e9bde..a4c55e1d7b 100644 --- a/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake +++ b/lib/kokkos/cmake/tpls/FindTPLHWLOC.cmake @@ -64,7 +64,7 @@ # Version: 1.3 # -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC +KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( HWLOC REQUIRED_HEADERS hwloc.h REQUIRED_LIBS_NAMES "hwloc" ) diff --git a/lib/kokkos/cmake/tpls/FindTPLPthread.cmake b/lib/kokkos/cmake/tpls/FindTPLPthread.cmake index fc401d7543..4dc1a87e18 100644 --- a/lib/kokkos/cmake/tpls/FindTPLPthread.cmake +++ b/lib/kokkos/cmake/tpls/FindTPLPthread.cmake @@ -75,7 +75,7 @@ IF(USE_THREADS) SET(TPL_Pthread_LIBRARIES "${CMAKE_THREAD_LIBS_INIT}") SET(TPL_Pthread_LIBRARY_DIRS "") ELSE() - TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread + KOKKOS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( Pthread REQUIRED_HEADERS pthread.h REQUIRED_LIBS_NAMES pthread ) diff --git a/lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake b/lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake deleted file mode 100644 index c312f2590b..0000000000 --- a/lib/kokkos/cmake/tpls/FindTPLQTHREADS.cmake +++ /dev/null @@ -1,69 +0,0 @@ -# @HEADER -# ************************************************************************ -# -# Trilinos: An Object-Oriented Solver Framework -# Copyright (2001) Sandia Corporation -# -# -# Copyright (2001) Sandia Corporation. Under the terms of Contract -# DE-AC04-94AL85000, there is a non-exclusive license for use of this -# work by or on behalf of the U.S. Government. Export of this program -# may require a license from the United States Government. -# -# 1. Redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer. -# -# 2. Redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution. -# -# 3. Neither the name of the Corporation nor the names of the -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY -# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE -# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# NOTICE: The United States Government is granted for itself and others -# acting on its behalf a paid-up, nonexclusive, irrevocable worldwide -# license in this data to reproduce, prepare derivative works, and -# perform publicly and display publicly. Beginning five (5) years from -# July 25, 2001, the United States Government is granted for itself and -# others acting on its behalf a paid-up, nonexclusive, irrevocable -# worldwide license in this data to reproduce, prepare derivative works, -# distribute copies to the public, perform publicly and display -# publicly, and to permit others to do so. -# -# NEITHER THE UNITED STATES GOVERNMENT, NOR THE UNITED STATES DEPARTMENT -# OF ENERGY, NOR SANDIA CORPORATION, NOR ANY OF THEIR EMPLOYEES, MAKES -# ANY WARRANTY, EXPRESS OR IMPLIED, OR ASSUMES ANY LEGAL LIABILITY OR -# RESPONSIBILITY FOR THE ACCURACY, COMPLETENESS, OR USEFULNESS OF ANY -# INFORMATION, APPARATUS, PRODUCT, OR PROCESS DISCLOSED, OR REPRESENTS -# THAT ITS USE WOULD NOT INFRINGE PRIVATELY OWNED RIGHTS. -# -# ************************************************************************ -# @HEADER - - -#----------------------------------------------------------------------------- -# Hardware locality detection and control library. -# -# Acquisition information: -# Date checked: July 2014 -# Checked by: H. Carter Edwards -# Source: https://code.google.com/p/qthreads -# - -TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES( QTHREADS - REQUIRED_HEADERS qthread.h - REQUIRED_LIBS_NAMES "qthread" - ) diff --git a/lib/kokkos/cmake/tribits.cmake b/lib/kokkos/cmake/tribits.cmake deleted file mode 100644 index 1f467f0662..0000000000 --- a/lib/kokkos/cmake/tribits.cmake +++ /dev/null @@ -1,531 +0,0 @@ -INCLUDE(CMakeParseArguments) -INCLUDE(CTest) - -cmake_policy(SET CMP0054 NEW) - -MESSAGE(STATUS "The project name is: ${PROJECT_NAME}") - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_OpenMP) - SET(${PROJECT_NAME}_ENABLE_OpenMP OFF) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_HPX) - SET(${PROJECT_NAME}_ENABLE_HPX OFF) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_DEBUG) - SET(${PROJECT_NAME}_ENABLE_DEBUG OFF) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_CXX11) - SET(${PROJECT_NAME}_ENABLE_CXX11 ON) -ENDIF() - -IF(NOT DEFINED ${PROJECT_NAME}_ENABLE_TESTS) - SET(${PROJECT_NAME}_ENABLE_TESTS OFF) -ENDIF() - -IF(NOT DEFINED TPL_ENABLE_Pthread) - SET(TPL_ENABLE_Pthread OFF) -ENDIF() - -FUNCTION(ASSERT_DEFINED VARS) - FOREACH(VAR ${VARS}) - IF(NOT DEFINED ${VAR}) - MESSAGE(SEND_ERROR "Error, the variable ${VAR} is not defined!") - ENDIF() - ENDFOREACH() -ENDFUNCTION() - -MACRO(GLOBAL_SET VARNAME) - SET(${VARNAME} ${ARGN} CACHE INTERNAL "") -ENDMACRO() - -MACRO(PREPEND_GLOBAL_SET VARNAME) - ASSERT_DEFINED(${VARNAME}) - GLOBAL_SET(${VARNAME} ${ARGN} ${${VARNAME}}) -ENDMACRO() - -#FUNCTION(REMOVE_GLOBAL_DUPLICATES VARNAME) -# ASSERT_DEFINED(${VARNAME}) -# IF (${VARNAME}) -# SET(TMP ${${VARNAME}}) -# LIST(REMOVE_DUPLICATES TMP) -# GLOBAL_SET(${VARNAME} ${TMP}) -# ENDIF() -#ENDFUNCTION() - -#MACRO(TRIBITS_ADD_OPTION_AND_DEFINE USER_OPTION_NAME MACRO_DEFINE_NAME DOCSTRING DEFAULT_VALUE) -# MESSAGE(STATUS "TRIBITS_ADD_OPTION_AND_DEFINE: '${USER_OPTION_NAME}' '${MACRO_DEFINE_NAME}' '${DEFAULT_VALUE}'") -# SET( ${USER_OPTION_NAME} "${DEFAULT_VALUE}" CACHE BOOL "${DOCSTRING}" ) -# IF(NOT ${MACRO_DEFINE_NAME} STREQUAL "") -# IF(${USER_OPTION_NAME}) -# GLOBAL_SET(${MACRO_DEFINE_NAME} ON) -# ELSE() -# GLOBAL_SET(${MACRO_DEFINE_NAME} OFF) -# ENDIF() -# ENDIF() -#ENDMACRO() - -FUNCTION(TRIBITS_CONFIGURE_FILE PACKAGE_NAME_CONFIG_FILE) - - # Configure the file - CONFIGURE_FILE( - ${PACKAGE_SOURCE_DIR}/cmake/${PACKAGE_NAME_CONFIG_FILE}.in - ${CMAKE_CURRENT_BINARY_DIR}/${PACKAGE_NAME_CONFIG_FILE} - ) - -ENDFUNCTION() - -#MACRO(TRIBITS_ADD_DEBUG_OPTION) -# TRIBITS_ADD_OPTION_AND_DEFINE( -# ${PROJECT_NAME}_ENABLE_DEBUG -# HAVE_${PROJECT_NAME_UC}_DEBUG -# "Enable a host of runtime debug checking." -# OFF -# ) -#ENDMACRO() - - -MACRO(TRIBITS_ADD_TEST_DIRECTORIES) - IF(${${PROJECT_NAME}_ENABLE_TESTS}) - FOREACH(TEST_DIR ${ARGN}) - ADD_SUBDIRECTORY(${TEST_DIR}) - ENDFOREACH() - ENDIF() -ENDMACRO() - -MACRO(TRIBITS_ADD_EXAMPLE_DIRECTORIES) - IF(${PACKAGE_NAME}_ENABLE_EXAMPLES OR ${PARENT_PACKAGE_NAME}_ENABLE_EXAMPLES) - FOREACH(EXAMPLE_DIR ${ARGN}) - ADD_SUBDIRECTORY(${EXAMPLE_DIR}) - ENDFOREACH() - ENDIF() -ENDMACRO() - - -function(INCLUDE_DIRECTORIES) - cmake_parse_arguments(INCLUDE_DIRECTORIES "REQUIRED_DURING_INSTALLATION_TESTING" "" "" ${ARGN}) - _INCLUDE_DIRECTORIES(${INCLUDE_DIRECTORIES_UNPARSED_ARGUMENTS}) -endfunction() - - -MACRO(TARGET_TRANSFER_PROPERTY TARGET_NAME PROP_IN PROP_OUT) - SET(PROP_VALUES) - FOREACH(TARGET_X ${ARGN}) - LIST(APPEND PROP_VALUES "$") - ENDFOREACH() - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES ${PROP_OUT} "${PROP_VALUES}") -ENDMACRO() - -MACRO(ADD_INTERFACE_LIBRARY LIB_NAME) - FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp "") - ADD_LIBRARY(${LIB_NAME} STATIC ${CMAKE_CURRENT_BINARY_DIR}/dummy.cpp) - SET_TARGET_PROPERTIES(${LIB_NAME} PROPERTIES INTERFACE TRUE) -ENDMACRO() - -# Older versions of cmake does not make include directories transitive -MACRO(TARGET_LINK_AND_INCLUDE_LIBRARIES TARGET_NAME) - TARGET_LINK_LIBRARIES(${TARGET_NAME} LINK_PUBLIC ${ARGN}) - FOREACH(DEP_LIB ${ARGN}) - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC $) - TARGET_INCLUDE_DIRECTORIES(${TARGET_NAME} PUBLIC $) - ENDFOREACH() -ENDMACRO() - -FUNCTION(TRIBITS_ADD_LIBRARY LIBRARY_NAME) - - SET(options STATIC SHARED TESTONLY NO_INSTALL_LIB_OR_HEADERS CUDALIBRARY) - SET(oneValueArgs) - SET(multiValueArgs HEADERS HEADERS_INSTALL_SUBDIR NOINSTALLHEADERS SOURCES DEPLIBS IMPORTEDLIBS DEFINES ADDED_LIB_TARGET_NAME_OUT) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - IF(PARSE_HEADERS) - LIST(REMOVE_DUPLICATES PARSE_HEADERS) - ENDIF() - IF(PARSE_SOURCES) - LIST(REMOVE_DUPLICATES PARSE_SOURCES) - ENDIF() - - # Local variable to hold all of the libraries that will be directly linked - # to this library. - SET(LINK_LIBS ${${PACKAGE_NAME}_DEPS}) - - # Add dependent libraries passed directly in - - IF (PARSE_IMPORTEDLIBS) - LIST(APPEND LINK_LIBS ${PARSE_IMPORTEDLIBS}) - ENDIF() - - IF (PARSE_DEPLIBS) - LIST(APPEND LINK_LIBS ${PARSE_DEPLIBS}) - ENDIF() - - # Add the library and all the dependencies - - IF (PARSE_DEFINES) - ADD_DEFINITIONS(${PARSE_DEFINES}) - ENDIF() - - IF (PARSE_STATIC) - SET(STATIC_KEYWORD "STATIC") - ELSE() - SET(STATIC_KEYWORD) - ENDIF() - - IF (PARSE_SHARED) - SET(SHARED_KEYWORD "SHARED") - ELSE() - SET(SHARED_KEYWORD) - ENDIF() - - IF (PARSE_TESTONLY) - SET(EXCLUDE_FROM_ALL_KEYWORD "EXCLUDE_FROM_ALL") - ELSE() - SET(EXCLUDE_FROM_ALL_KEYWORD) - ENDIF() - IF (NOT PARSE_CUDALIBRARY) - ADD_LIBRARY( - ${LIBRARY_NAME} - ${STATIC_KEYWORD} - ${SHARED_KEYWORD} - ${EXCLUDE_FROM_ALL_KEYWORD} - ${PARSE_HEADERS} - ${PARSE_NOINSTALLHEADERS} - ${PARSE_SOURCES} - ) - ELSE() - CUDA_ADD_LIBRARY( - ${LIBRARY_NAME} - ${PARSE_HEADERS} - ${PARSE_NOINSTALLHEADERS} - ${PARSE_SOURCES} - ) - ENDIF() - - TARGET_LINK_AND_INCLUDE_LIBRARIES(${LIBRARY_NAME} ${LINK_LIBS}) - - IF (NOT PARSE_TESTONLY OR PARSE_NO_INSTALL_LIB_OR_HEADERS) - - INSTALL( - TARGETS ${LIBRARY_NAME} - EXPORT ${PROJECT_NAME} - RUNTIME DESTINATION bin - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - COMPONENT ${PACKAGE_NAME} - ) - - INSTALL( - FILES ${PARSE_HEADERS} - EXPORT ${PROJECT_NAME} - DESTINATION include - COMPONENT ${PACKAGE_NAME} - ) - - INSTALL( - DIRECTORY ${PARSE_HEADERS_INSTALL_SUBDIR} - EXPORT ${PROJECT_NAME} - DESTINATION include - COMPONENT ${PACKAGE_NAME} - ) - - ENDIF() - - IF (NOT PARSE_TESTONLY) - PREPEND_GLOBAL_SET(${PACKAGE_NAME}_LIBS ${LIBRARY_NAME}) - REMOVE_GLOBAL_DUPLICATES(${PACKAGE_NAME}_LIBS) - ENDIF() - -ENDFUNCTION() - -FUNCTION(TRIBITS_ADD_EXECUTABLE EXE_NAME) - - SET(options NOEXEPREFIX NOEXESUFFIX ADD_DIR_TO_NAME INSTALLABLE TESTONLY) - SET(oneValueArgs ADDED_EXE_TARGET_NAME_OUT) - SET(multiValueArgs SOURCES CATEGORIES HOST XHOST HOSTTYPE XHOSTTYPE DIRECTORY TESTONLYLIBS IMPORTEDLIBS DEPLIBS COMM LINKER_LANGUAGE TARGET_DEFINES DEFINES) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - IF (PARSE_TARGET_DEFINES) - TARGET_COMPILE_DEFINITIONS(${EXE_NAME} PUBLIC ${PARSE_TARGET_DEFINES}) - ENDIF() - - SET(LINK_LIBS PACKAGE_${PACKAGE_NAME}) - - IF (PARSE_TESTONLYLIBS) - LIST(APPEND LINK_LIBS ${PARSE_TESTONLYLIBS}) - ENDIF() - - IF (PARSE_IMPORTEDLIBS) - LIST(APPEND LINK_LIBS ${PARSE_IMPORTEDLIBS}) - ENDIF() - - SET (EXE_SOURCES) - IF(PARSE_DIRECTORY) - FOREACH( SOURCE_FILE ${PARSE_SOURCES} ) - IF(IS_ABSOLUTE ${SOURCE_FILE}) - SET (EXE_SOURCES ${EXE_SOURCES} ${SOURCE_FILE}) - ELSE() - SET (EXE_SOURCES ${EXE_SOURCES} ${PARSE_DIRECTORY}/${SOURCE_FILE}) - ENDIF() - ENDFOREACH( ) - ELSE() - FOREACH( SOURCE_FILE ${PARSE_SOURCES} ) - SET (EXE_SOURCES ${EXE_SOURCES} ${SOURCE_FILE}) - ENDFOREACH( ) - ENDIF() - - SET(EXE_BINARY_NAME ${EXE_NAME}) - IF(DEFINED PACKAGE_NAME AND NOT PARSE_NOEXEPREFIX) - SET(EXE_BINARY_NAME ${PACKAGE_NAME}_${EXE_BINARY_NAME}) - ENDIF() - - # IF (PARSE_TESTONLY) - # SET(EXCLUDE_FROM_ALL_KEYWORD "EXCLUDE_FROM_ALL") - # ELSE() - # SET(EXCLUDE_FROM_ALL_KEYWORD) - # ENDIF() - ADD_EXECUTABLE(${EXE_BINARY_NAME} ${EXCLUDE_FROM_ALL_KEYWORD} ${EXE_SOURCES}) - - TARGET_LINK_AND_INCLUDE_LIBRARIES(${EXE_BINARY_NAME} ${LINK_LIBS}) - - IF(PARSE_ADDED_EXE_TARGET_NAME_OUT) - SET(${PARSE_ADDED_EXE_TARGET_NAME_OUT} ${EXE_BINARY_NAME} PARENT_SCOPE) - ENDIF() - - IF(PARSE_INSTALLABLE) - INSTALL( - TARGETS ${EXE_BINARY_NAME} - EXPORT ${PROJECT_NAME} - DESTINATION bin - ) - ENDIF() -ENDFUNCTION() - -IF(NOT TARGET check) - ADD_CUSTOM_TARGET(check COMMAND ${CMAKE_CTEST_COMMAND} -VV -C ${CMAKE_CFG_INTDIR}) -ENDIF() - -FUNCTION(TRIBITS_ADD_TEST) -ENDFUNCTION() -FUNCTION(TRIBITS_TPL_TENTATIVELY_ENABLE) -ENDFUNCTION() - -FUNCTION(TRIBITS_ADD_ADVANCED_TEST) - # TODO Write this -ENDFUNCTION() - -FUNCTION(TRIBITS_ADD_EXECUTABLE_AND_TEST EXE_NAME) - - SET(options STANDARD_PASS_OUTPUT WILL_FAIL) - SET(oneValueArgs PASS_REGULAR_EXPRESSION FAIL_REGULAR_EXPRESSION ENVIRONMENT TIMEOUT CATEGORIES ADDED_TESTS_NAMES_OUT ADDED_EXE_TARGET_NAME_OUT) - SET(multiValueArgs) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - TRIBITS_ADD_EXECUTABLE(${EXE_NAME} TESTONLY ADDED_EXE_TARGET_NAME_OUT TEST_NAME ${PARSE_UNPARSED_ARGUMENTS}) - - IF(WIN32) - ADD_TEST(NAME ${TEST_NAME} WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH} COMMAND ${TEST_NAME}${CMAKE_EXECUTABLE_SUFFIX}) - ELSE() - ADD_TEST(NAME ${TEST_NAME} COMMAND ${TEST_NAME}) - ENDIF() - ADD_DEPENDENCIES(check ${TEST_NAME}) - - IF(PARSE_FAIL_REGULAR_EXPRESSION) - SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES FAIL_REGULAR_EXPRESSION ${PARSE_FAIL_REGULAR_EXPRESSION}) - ENDIF() - - IF(PARSE_PASS_REGULAR_EXPRESSION) - SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES PASS_REGULAR_EXPRESSION ${PARSE_PASS_REGULAR_EXPRESSION}) - ENDIF() - - IF(PARSE_WILL_FAIL) - SET_TESTS_PROPERTIES(${TEST_NAME} PROPERTIES WILL_FAIL ${PARSE_WILL_FAIL}) - ENDIF() - - IF(PARSE_ADDED_TESTS_NAMES_OUT) - SET(${PARSE_ADDED_TESTS_NAMES_OUT} ${TEST_NAME} PARENT_SCOPE) - ENDIF() - - IF(PARSE_ADDED_EXE_TARGET_NAME_OUT) - SET(${PARSE_ADDED_EXE_TARGET_NAME_OUT} ${TEST_NAME} PARENT_SCOPE) - ENDIF() - -ENDFUNCTION() - -MACRO(TIBITS_CREATE_IMPORTED_TPL_LIBRARY TPL_NAME) - ADD_INTERFACE_LIBRARY(TPL_LIB_${TPL_NAME}) - TARGET_LINK_LIBRARIES(TPL_LIB_${TPL_NAME} LINK_PUBLIC ${TPL_${TPL_NAME}_LIBRARIES}) - TARGET_INCLUDE_DIRECTORIES(TPL_LIB_${TPL_NAME} INTERFACE ${TPL_${TPL_NAME}_INCLUDE_DIRS}) -ENDMACRO() - -FUNCTION(TRIBITS_TPL_FIND_INCLUDE_DIRS_AND_LIBRARIES TPL_NAME) - - SET(options MUST_FIND_ALL_LIBS MUST_FIND_ALL_HEADERS NO_PRINT_ENABLE_SUCCESS_FAIL) - SET(oneValueArgs) - SET(multiValueArgs REQUIRED_HEADERS REQUIRED_LIBS_NAMES) - - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - SET(_${TPL_NAME}_ENABLE_SUCCESS TRUE) - IF (PARSE_REQUIRED_LIBS_NAMES) - FIND_LIBRARY(TPL_${TPL_NAME}_LIBRARIES NAMES ${PARSE_REQUIRED_LIBS_NAMES}) - IF(NOT TPL_${TPL_NAME}_LIBRARIES) - SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) - ENDIF() - ENDIF() - IF (PARSE_REQUIRED_HEADERS) - FIND_PATH(TPL_${TPL_NAME}_INCLUDE_DIRS NAMES ${PARSE_REQUIRED_HEADERS}) - IF(NOT TPL_${TPL_NAME}_INCLUDE_DIRS) - SET(_${TPL_NAME}_ENABLE_SUCCESS FALSE) - ENDIF() - ENDIF() - - - IF (_${TPL_NAME}_ENABLE_SUCCESS) - TIBITS_CREATE_IMPORTED_TPL_LIBRARY(${TPL_NAME}) - ENDIF() - -ENDFUNCTION() - -#MACRO(TRIBITS_PROCESS_TPL_DEP_FILE TPL_FILE) -# GET_FILENAME_COMPONENT(TPL_NAME ${TPL_FILE} NAME_WE) -# INCLUDE("${TPL_FILE}") -# IF(TARGET TPL_LIB_${TPL_NAME}) -# MESSAGE(STATUS "Found tpl library: ${TPL_NAME}") -# SET(TPL_ENABLE_${TPL_NAME} TRUE) -# ELSE() -# MESSAGE(STATUS "Tpl library not found: ${TPL_NAME}") -# SET(TPL_ENABLE_${TPL_NAME} FALSE) -# ENDIF() -#ENDMACRO() - -MACRO(PREPEND_TARGET_SET VARNAME TARGET_NAME TYPE) - IF(TYPE STREQUAL "REQUIRED") - SET(REQUIRED TRUE) - ELSE() - SET(REQUIRED FALSE) - ENDIF() - IF(TARGET ${TARGET_NAME}) - PREPEND_GLOBAL_SET(${VARNAME} ${TARGET_NAME}) - ELSE() - IF(REQUIRED) - MESSAGE(FATAL_ERROR "Missing dependency ${TARGET_NAME}") - ENDIF() - ENDIF() -ENDMACRO() - -MACRO(TRIBITS_APPEND_PACKAGE_DEPS DEP_LIST TYPE) - FOREACH(DEP ${ARGN}) - PREPEND_GLOBAL_SET(${DEP_LIST} PACKAGE_${DEP}) - ENDFOREACH() -ENDMACRO() - -MACRO(TRIBITS_APPEND_TPLS_DEPS DEP_LIST TYPE) - FOREACH(DEP ${ARGN}) - PREPEND_TARGET_SET(${DEP_LIST} TPL_LIB_${DEP} ${TYPE}) - ENDFOREACH() -ENDMACRO() - -MACRO(TRIBITS_ENABLE_TPLS) - FOREACH(TPL ${ARGN}) - IF(TARGET ${TPL}) - GLOBAL_SET(${PACKAGE_NAME}_ENABLE_${TPL} TRUE) - ELSE() - GLOBAL_SET(${PACKAGE_NAME}_ENABLE_${TPL} FALSE) - ENDIF() - ENDFOREACH() -ENDMACRO() - -MACRO(TRIBITS_PACKAGE_DEFINE_DEPENDENCIES) - - SET(options) - SET(oneValueArgs) - SET(multiValueArgs - LIB_REQUIRED_PACKAGES - LIB_OPTIONAL_PACKAGES - TEST_REQUIRED_PACKAGES - TEST_OPTIONAL_PACKAGES - LIB_REQUIRED_TPLS - LIB_OPTIONAL_TPLS - TEST_REQUIRED_TPLS - TEST_OPTIONAL_TPLS - REGRESSION_EMAIL_LIST - SUBPACKAGES_DIRS_CLASSIFICATIONS_OPTREQS - ) - CMAKE_PARSE_ARGUMENTS(PARSE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) - - GLOBAL_SET(${PACKAGE_NAME}_DEPS "") - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_DEPS REQUIRED ${PARSE_LIB_REQUIRED_PACKAGES}) - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_DEPS OPTIONAL ${PARSE_LIB_OPTIONAL_PACKAGES}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_DEPS REQUIRED ${PARSE_LIB_REQUIRED_TPLS}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_DEPS OPTIONAL ${PARSE_LIB_OPTIONAL_TPLS}) - - GLOBAL_SET(${PACKAGE_NAME}_TEST_DEPS "") - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_TEST_DEPS REQUIRED ${PARSE_TEST_REQUIRED_PACKAGES}) - TRIBITS_APPEND_PACKAGE_DEPS(${PACKAGE_NAME}_TEST_DEPS OPTIONAL ${PARSE_TEST_OPTIONAL_PACKAGES}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_TEST_DEPS REQUIRED ${PARSE_TEST_REQUIRED_TPLS}) - TRIBITS_APPEND_TPLS_DEPS(${PACKAGE_NAME}_TEST_DEPS OPTIONAL ${PARSE_TEST_OPTIONAL_TPLS}) - - TRIBITS_ENABLE_TPLS(${PARSE_LIB_REQUIRED_TPLS} ${PARSE_LIB_OPTIONAL_TPLS} ${PARSE_TEST_REQUIRED_TPLS} ${PARSE_TEST_OPTIONAL_TPLS}) - -ENDMACRO() - -MACRO(TRIBITS_SUBPACKAGE NAME) - SET(PACKAGE_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - SET(PARENT_PACKAGE_NAME ${PACKAGE_NAME}) - SET(PACKAGE_NAME ${PACKAGE_NAME}${NAME}) - STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) - SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - - ADD_INTERFACE_LIBRARY(PACKAGE_${PACKAGE_NAME}) - - GLOBAL_SET(${PACKAGE_NAME}_LIBS "") - - INCLUDE(${PACKAGE_SOURCE_DIR}/cmake/Dependencies.cmake) - -ENDMACRO(TRIBITS_SUBPACKAGE) - -MACRO(TRIBITS_SUBPACKAGE_POSTPROCESS) - TARGET_LINK_AND_INCLUDE_LIBRARIES(PACKAGE_${PACKAGE_NAME} ${${PACKAGE_NAME}_LIBS}) -ENDMACRO(TRIBITS_SUBPACKAGE_POSTPROCESS) - -MACRO(TRIBITS_PACKAGE_DECL NAME) - - SET(PACKAGE_NAME ${NAME}) - SET(${PACKAGE_NAME}_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) - STRING(TOUPPER ${PACKAGE_NAME} PACKAGE_NAME_UC) - - #SET(TRIBITS_DEPS_DIR "${CMAKE_SOURCE_DIR}/cmake/deps") - #FILE(GLOB TPLS_FILES "${TRIBITS_DEPS_DIR}/*.cmake") - #FOREACH(TPL_FILE ${TPLS_FILES}) - # TRIBITS_PROCESS_TPL_DEP_FILE(${TPL_FILE}) - #ENDFOREACH() - -ENDMACRO() - - -MACRO(TRIBITS_PROCESS_SUBPACKAGES) - FILE(GLOB SUBPACKAGES RELATIVE ${CMAKE_SOURCE_DIR} */cmake/Dependencies.cmake) - FOREACH(SUBPACKAGE ${SUBPACKAGES}) - GET_FILENAME_COMPONENT(SUBPACKAGE_CMAKE ${SUBPACKAGE} DIRECTORY) - GET_FILENAME_COMPONENT(SUBPACKAGE_DIR ${SUBPACKAGE_CMAKE} DIRECTORY) - ADD_SUBDIRECTORY(${CMAKE_BINARY_DIR}/../${SUBPACKAGE_DIR}) - ENDFOREACH() -ENDMACRO(TRIBITS_PROCESS_SUBPACKAGES) - -MACRO(TRIBITS_PACKAGE_DEF) -ENDMACRO(TRIBITS_PACKAGE_DEF) - -MACRO(TRIBITS_EXCLUDE_AUTOTOOLS_FILES) -ENDMACRO(TRIBITS_EXCLUDE_AUTOTOOLS_FILES) - -MACRO(TRIBITS_EXCLUDE_FILES) -ENDMACRO(TRIBITS_EXCLUDE_FILES) - -MACRO(TRIBITS_PACKAGE_POSTPROCESS) -ENDMACRO(TRIBITS_PACKAGE_POSTPROCESS) - diff --git a/lib/kokkos/containers/CMakeLists.txt b/lib/kokkos/containers/CMakeLists.txt index c37aa3e3e2..2bfaea7a13 100644 --- a/lib/kokkos/containers/CMakeLists.txt +++ b/lib/kokkos/containers/CMakeLists.txt @@ -1,13 +1,10 @@ - - -TRIBITS_SUBPACKAGE(Containers) - - -IF(KOKKOS_HAS_TRILINOS) - ADD_SUBDIRECTORY(src) -ENDIF() - -TRIBITS_ADD_TEST_DIRECTORIES(unit_tests) -TRIBITS_ADD_TEST_DIRECTORIES(performance_tests) - -TRIBITS_SUBPACKAGE_POSTPROCESS() + + +KOKKOS_SUBPACKAGE(Containers) + +ADD_SUBDIRECTORY(src) + +KOKKOS_ADD_TEST_DIRECTORIES(unit_tests) +KOKKOS_ADD_TEST_DIRECTORIES(performance_tests) + +KOKKOS_SUBPACKAGE_POSTPROCESS() diff --git a/lib/kokkos/containers/performance_tests/CMakeLists.txt b/lib/kokkos/containers/performance_tests/CMakeLists.txt index 3c6584bc34..ca76808190 100644 --- a/lib/kokkos/containers/performance_tests/CMakeLists.txt +++ b/lib/kokkos/containers/performance_tests/CMakeLists.txt @@ -1,49 +1,62 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) - -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) + +IF(Kokkos_ENABLE_CUDA) + SET(SOURCES + TestMain.cpp + TestCuda.cpp + ) + + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_Cuda + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_Cuda + EXE PerfTestExec_Cuda + ) ENDIF() -SET(SOURCES - TestMain.cpp - TestCuda.cpp - ) - -IF(Kokkos_ENABLE_Pthread) - LIST( APPEND SOURCES TestThreads.cpp) +IF(Kokkos_ENABLE_PTHREAD) + SET(SOURCES + TestMain.cpp + TestThreads.cpp + ) + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_Threads + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_Threads + EXE PerfTestExec_Threads + ) ENDIF() -IF(Kokkos_ENABLE_OpenMP) - LIST( APPEND SOURCES TestOpenMP.cpp) +IF(Kokkos_ENABLE_OPENMP) + SET(SOURCES + TestMain.cpp + TestOpenMP.cpp + ) + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_OpenMP + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_OpenMP + EXE PerfTestExec_OpenMP + ) ENDIF() IF(Kokkos_ENABLE_HPX) - LIST( APPEND SOURCES TestHPX.cpp) + SET(SOURCES + TestMain.cpp + TestHPX.cpp + ) + KOKKOS_ADD_TEST_EXECUTABLE( PerfTestExec_HPX + SOURCES ${SOURCES} + ) + + KOKKOS_ADD_TEST( NAME PerformanceTest_HPX + EXE PerfTestExec_HPX + ) ENDIF() -# Per #374, we always want to build this test, but we only want to run -# it as a PERFORMANCE test. That's why we separate building the test -# from running the test. - -TRIBITS_ADD_EXECUTABLE( - PerfTestExec - SOURCES ${SOURCES} - COMM serial mpi - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) - -TRIBITS_ADD_TEST( - PerformanceTest - NAME PerfTestExec - COMM serial mpi - NUM_MPI_PROCS 1 - CATEGORIES PERFORMANCE - FAIL_REGULAR_EXPRESSION " FAILED " - ) diff --git a/lib/kokkos/containers/performance_tests/TestCuda.cpp b/lib/kokkos/containers/performance_tests/TestCuda.cpp index 351fb86df3..697a006c3c 100644 --- a/lib/kokkos/containers/performance_tests/TestCuda.cpp +++ b/lib/kokkos/containers/performance_tests/TestCuda.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include #include @@ -66,45 +67,38 @@ namespace Performance { class cuda : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::InitArguments args(-1, -1, 0); Kokkos::initialize(args); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( cuda, dynrankview_perf ) -{ +TEST_F(cuda, dynrankview_perf) { std::cout << "Cuda" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 40960 ); + test_dynrankview_op_perf(40960); } -TEST_F( cuda, global_2_local) -{ +TEST_F(cuda, global_2_local) { std::cout << "Cuda" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( cuda, unordered_map_performance_near) -{ - Perf::run_performance_tests("cuda-near"); +TEST_F(cuda, unordered_map_performance_near) { + Perf::run_performance_tests("cuda-near"); } -TEST_F( cuda, unordered_map_performance_far) -{ - Perf::run_performance_tests("cuda-far"); +TEST_F(cuda, unordered_map_performance_far) { + Perf::run_performance_tests("cuda-far"); } -} +} // namespace Performance #else void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTCUDA_PREVENT_EMPTY_LINK_ERROR() {} -#endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ +#endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ diff --git a/lib/kokkos/containers/performance_tests/TestDynRankView.hpp b/lib/kokkos/containers/performance_tests/TestDynRankView.hpp index db6274e057..ee13f7e58b 100644 --- a/lib/kokkos/containers/performance_tests/TestDynRankView.hpp +++ b/lib/kokkos/containers/performance_tests/TestDynRankView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,109 +50,102 @@ #include -// Compare performance of DynRankView to View, specific focus on the parenthesis operators +// Compare performance of DynRankView to View, specific focus on the parenthesis +// operators namespace Performance { -//View functor +// View functor template struct InitViewFunctor { - typedef Kokkos::View inviewtype; + typedef Kokkos::View inviewtype; inviewtype _inview; - InitViewFunctor( inviewtype &inview_ ) : _inview(inview_) - {} + InitViewFunctor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k) = i/2 -j*j + k/3; + _inview(i, j, k) = i / 2 - j * j + k / 3; } } } - struct SumComputationTest - { - typedef Kokkos::View inviewtype; + struct SumComputationTest { + typedef Kokkos::View inviewtype; inviewtype _inview; - typedef Kokkos::View outviewtype; + typedef Kokkos::View outviewtype; outviewtype _outview; KOKKOS_INLINE_FUNCTION - SumComputationTest(inviewtype &inview_ , outviewtype &outview_) : _inview(inview_), _outview(outview_) {} + SumComputationTest(inviewtype &inview_, outviewtype &outview_) + : _inview(inview_), _outview(outview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _outview(i) += _inview(i,j,k) ; + _outview(i) += _inview(i, j, k); } } } }; - }; template struct InitStrideViewFunctor { - typedef Kokkos::View inviewtype; + typedef Kokkos::View inviewtype; inviewtype _inview; - InitStrideViewFunctor( inviewtype &inview_ ) : _inview(inview_) - {} + InitStrideViewFunctor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k) = i/2 -j*j + k/3; + _inview(i, j, k) = i / 2 - j * j + k / 3; } } } - }; template struct InitViewRank7Functor { - typedef Kokkos::View inviewtype; + typedef Kokkos::View inviewtype; inviewtype _inview; - InitViewRank7Functor( inviewtype &inview_ ) : _inview(inview_) - {} + InitViewRank7Functor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k,0,0,0,0) = i/2 -j*j + k/3; + _inview(i, j, k, 0, 0, 0, 0) = i / 2 - j * j + k / 3; } } } - }; -//DynRankView functor +// DynRankView functor template struct InitDynRankViewFunctor { typedef Kokkos::DynRankView inviewtype; inviewtype _inview; - InitDynRankViewFunctor( inviewtype &inview_ ) : _inview(inview_) - {} + InitDynRankViewFunctor(inviewtype &inview_) : _inview(inview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _inview(i,j,k) = i/2 -j*j + k/3; + _inview(i, j, k) = i / 2 - j * j + k / 3; } } } - struct SumComputationTest - { + struct SumComputationTest { typedef Kokkos::DynRankView inviewtype; inviewtype _inview; @@ -159,108 +153,121 @@ struct InitDynRankViewFunctor { outviewtype _outview; KOKKOS_INLINE_FUNCTION - SumComputationTest(inviewtype &inview_ , outviewtype &outview_) : _inview(inview_), _outview(outview_) {} + SumComputationTest(inviewtype &inview_, outviewtype &outview_) + : _inview(inview_), _outview(outview_) {} KOKKOS_INLINE_FUNCTION void operator()(const int i) const { for (unsigned j = 0; j < _inview.extent(1); ++j) { for (unsigned k = 0; k < _inview.extent(2); ++k) { - _outview(i) += _inview(i,j,k) ; + _outview(i) += _inview(i, j, k); } } } }; - }; - template -void test_dynrankview_op_perf( const int par_size ) -{ - +void test_dynrankview_op_perf(const int par_size) { typedef DeviceType execution_space; typedef typename execution_space::size_type size_type; const size_type dim_2 = 90; const size_type dim_3 = 30; - double elapsed_time_view = 0; - double elapsed_time_compview = 0; + double elapsed_time_view = 0; + double elapsed_time_compview = 0; double elapsed_time_strideview = 0; double elapsed_time_view_rank7 = 0; - double elapsed_time_drview = 0; + double elapsed_time_drview = 0; double elapsed_time_compdrview = 0; Kokkos::Timer timer; { - Kokkos::View testview("testview",par_size,dim_2,dim_3); + Kokkos::View testview("testview", par_size, dim_2, + dim_3); typedef InitViewFunctor FunctorType; timer.reset(); - Kokkos::RangePolicy policy(0,par_size); - Kokkos::parallel_for( policy , FunctorType(testview) ); + Kokkos::RangePolicy policy(0, par_size); + Kokkos::parallel_for(policy, FunctorType(testview)); DeviceType().fence(); elapsed_time_view = timer.seconds(); std::cout << " View time (init only): " << elapsed_time_view << std::endl; - timer.reset(); - Kokkos::View sumview("sumview",par_size); - Kokkos::parallel_for( policy , typename FunctorType::SumComputationTest(testview, sumview) ); + Kokkos::View sumview("sumview", par_size); + Kokkos::parallel_for( + policy, typename FunctorType::SumComputationTest(testview, sumview)); DeviceType().fence(); elapsed_time_compview = timer.seconds(); - std::cout << " View sum computation time: " << elapsed_time_view << std::endl; - + std::cout << " View sum computation time: " << elapsed_time_view + << std::endl; - Kokkos::View teststrideview = Kokkos::subview(testview, Kokkos::ALL, Kokkos::ALL,Kokkos::ALL); + Kokkos::View teststrideview = + Kokkos::subview(testview, Kokkos::ALL, Kokkos::ALL, Kokkos::ALL); typedef InitStrideViewFunctor FunctorStrideType; timer.reset(); - Kokkos::parallel_for( policy , FunctorStrideType(teststrideview) ); + Kokkos::parallel_for(policy, FunctorStrideType(teststrideview)); DeviceType().fence(); elapsed_time_strideview = timer.seconds(); - std::cout << " Strided View time (init only): " << elapsed_time_strideview << std::endl; + std::cout << " Strided View time (init only): " << elapsed_time_strideview + << std::endl; } { - Kokkos::View testview("testview",par_size,dim_2,dim_3,1,1,1,1); + Kokkos::View testview("testview", par_size, + dim_2, dim_3, 1, 1, 1, 1); typedef InitViewRank7Functor FunctorType; timer.reset(); - Kokkos::RangePolicy policy(0,par_size); - Kokkos::parallel_for( policy , FunctorType(testview) ); + Kokkos::RangePolicy policy(0, par_size); + Kokkos::parallel_for(policy, FunctorType(testview)); DeviceType().fence(); elapsed_time_view_rank7 = timer.seconds(); - std::cout << " View Rank7 time (init only): " << elapsed_time_view_rank7 << std::endl; + std::cout << " View Rank7 time (init only): " << elapsed_time_view_rank7 + << std::endl; } { - Kokkos::DynRankView testdrview("testdrview",par_size,dim_2,dim_3); + Kokkos::DynRankView testdrview("testdrview", par_size, + dim_2, dim_3); typedef InitDynRankViewFunctor FunctorType; timer.reset(); - Kokkos::RangePolicy policy(0,par_size); - Kokkos::parallel_for( policy , FunctorType(testdrview) ); + Kokkos::RangePolicy policy(0, par_size); + Kokkos::parallel_for(policy, FunctorType(testdrview)); DeviceType().fence(); elapsed_time_drview = timer.seconds(); - std::cout << " DynRankView time (init only): " << elapsed_time_drview << std::endl; + std::cout << " DynRankView time (init only): " << elapsed_time_drview + << std::endl; timer.reset(); - Kokkos::DynRankView sumview("sumview",par_size); - Kokkos::parallel_for( policy , typename FunctorType::SumComputationTest(testdrview, sumview) ); + Kokkos::DynRankView sumview("sumview", par_size); + Kokkos::parallel_for( + policy, typename FunctorType::SumComputationTest(testdrview, sumview)); DeviceType().fence(); elapsed_time_compdrview = timer.seconds(); - std::cout << " DynRankView sum computation time: " << elapsed_time_compdrview << std::endl; - + std::cout << " DynRankView sum computation time: " + << elapsed_time_compdrview << std::endl; } - std::cout << " Ratio of View to DynRankView time: " << elapsed_time_view / elapsed_time_drview << std::endl; //expect < 1 - std::cout << " Ratio of View to DynRankView sum computation time: " << elapsed_time_compview / elapsed_time_compdrview << std::endl; //expect < 1 - std::cout << " Ratio of View to View Rank7 time: " << elapsed_time_view / elapsed_time_view_rank7 << std::endl; //expect < 1 - std::cout << " Ratio of StrideView to DynRankView time: " << elapsed_time_strideview / elapsed_time_drview << std::endl; //expect < 1 - std::cout << " Ratio of DynRankView to View Rank7 time: " << elapsed_time_drview / elapsed_time_view_rank7 << std::endl; //expect ? + std::cout << " Ratio of View to DynRankView time: " + << elapsed_time_view / elapsed_time_drview + << std::endl; // expect < 1 + std::cout << " Ratio of View to DynRankView sum computation time: " + << elapsed_time_compview / elapsed_time_compdrview + << std::endl; // expect < 1 + std::cout << " Ratio of View to View Rank7 time: " + << elapsed_time_view / elapsed_time_view_rank7 + << std::endl; // expect < 1 + std::cout << " Ratio of StrideView to DynRankView time: " + << elapsed_time_strideview / elapsed_time_drview + << std::endl; // expect < 1 + std::cout << " Ratio of DynRankView to View Rank7 time: " + << elapsed_time_drview / elapsed_time_view_rank7 + << std::endl; // expect ? timer.reset(); -} //end test_dynrankview - +} // end test_dynrankview -} //end Performance +} // namespace Performance #endif - diff --git a/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp b/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp index 98997b3239..0d2ee4bc8d 100644 --- a/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp +++ b/lib/kokkos/containers/performance_tests/TestGlobal2LocalIds.hpp @@ -1,12 +1,13 @@ //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -35,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER @@ -54,153 +55,137 @@ namespace Performance { static const unsigned begin_id_size = 256u; -static const unsigned end_id_size = 1u << 22; -static const unsigned id_step = 2u; +static const unsigned end_id_size = 1u << 22; +static const unsigned id_step = 2u; -union helper -{ +union helper { uint32_t word; uint8_t byte[4]; }; - template -struct generate_ids -{ +struct generate_ids { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; + typedef Kokkos::View local_id_view; local_id_view local_2_global; - generate_ids( local_id_view & ids) - : local_2_global(ids) - { + generate_ids(local_id_view& ids) : local_2_global(ids) { Kokkos::parallel_for(local_2_global.extent(0), *this); } - KOKKOS_INLINE_FUNCTION - void operator()(size_type i) const - { - + void operator()(size_type i) const { helper x = {static_cast(i)}; // shuffle the bytes of i to create a unique, semi-random global_id x.word = ~x.word; uint8_t tmp = x.byte[3]; - x.byte[3] = x.byte[1]; - x.byte[1] = tmp; + x.byte[3] = x.byte[1]; + x.byte[1] = tmp; - tmp = x.byte[2]; + tmp = x.byte[2]; x.byte[2] = x.byte[0]; x.byte[0] = tmp; local_2_global[i] = x.word; } - }; template -struct fill_map -{ +struct fill_map { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; - typedef Kokkos::UnorderedMap global_id_view; + typedef Kokkos::View + local_id_view; + typedef Kokkos::UnorderedMap + global_id_view; global_id_view global_2_local; local_id_view local_2_global; - fill_map( global_id_view gIds, local_id_view lIds) - : global_2_local(gIds) , local_2_global(lIds) - { + fill_map(global_id_view gIds, local_id_view lIds) + : global_2_local(gIds), local_2_global(lIds) { Kokkos::parallel_for(local_2_global.extent(0), *this); } KOKKOS_INLINE_FUNCTION - void operator()(size_type i) const - { - global_2_local.insert( local_2_global[i], i); + void operator()(size_type i) const { + global_2_local.insert(local_2_global[i], i); } - }; template -struct find_test -{ +struct find_test { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; - typedef Kokkos::UnorderedMap global_id_view; + typedef Kokkos::View + local_id_view; + typedef Kokkos::UnorderedMap + global_id_view; global_id_view global_2_local; local_id_view local_2_global; typedef size_t value_type; - find_test( global_id_view gIds, local_id_view lIds, value_type & num_errors) - : global_2_local(gIds) , local_2_global(lIds) - { + find_test(global_id_view gIds, local_id_view lIds, value_type& num_errors) + : global_2_local(gIds), local_2_global(lIds) { Kokkos::parallel_reduce(local_2_global.extent(0), *this, num_errors); } KOKKOS_INLINE_FUNCTION - void init(value_type & v) const - { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join(volatile value_type & dst, volatile value_type const & src) const - { dst += src; } + void join(volatile value_type& dst, volatile value_type const& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(size_type i, value_type & num_errors) const - { - uint32_t index = global_2_local.find( local_2_global[i] ); + void operator()(size_type i, value_type& num_errors) const { + uint32_t index = global_2_local.find(local_2_global[i]); - if ( global_2_local.value_at(index) != i) ++num_errors; + if (global_2_local.value_at(index) != i) ++num_errors; } - }; template -void test_global_to_local_ids(unsigned num_ids) -{ - +void test_global_to_local_ids(unsigned num_ids) { typedef Device execution_space; typedef typename execution_space::size_type size_type; - typedef Kokkos::View local_id_view; - typedef Kokkos::UnorderedMap global_id_view; + typedef Kokkos::View local_id_view; + typedef Kokkos::UnorderedMap + global_id_view; - //size + // size std::cout << num_ids << ", "; double elasped_time = 0; Kokkos::Timer timer; local_id_view local_2_global("local_ids", num_ids); - global_id_view global_2_local((3u*num_ids)/2u); + global_id_view global_2_local((3u * num_ids) / 2u); - //create + // create elasped_time = timer.seconds(); std::cout << elasped_time << ", "; timer.reset(); // generate unique ids - { - generate_ids gen(local_2_global); - } + { generate_ids gen(local_2_global); } Device().fence(); // generate elasped_time = timer.seconds(); std::cout << elasped_time << ", "; timer.reset(); - { - fill_map fill(global_2_local, local_2_global); - } + { fill_map fill(global_2_local, local_2_global); } Device().fence(); // fill @@ -208,11 +193,9 @@ void test_global_to_local_ids(unsigned num_ids) std::cout << elasped_time << ", "; timer.reset(); - size_t num_errors = 0; - for (int i=0; i<100; ++i) - { - find_test find(global_2_local, local_2_global,num_errors); + for (int i = 0; i < 100; ++i) { + find_test find(global_2_local, local_2_global, num_errors); } Device().fence(); @@ -220,12 +203,9 @@ void test_global_to_local_ids(unsigned num_ids) elasped_time = timer.seconds(); std::cout << elasped_time << std::endl; - ASSERT_EQ( num_errors, 0u); + ASSERT_EQ(num_errors, 0u); } +} // namespace Performance -} // namespace Performance - - -#endif //KOKKOS_TEST_GLOBAL_TO_LOCAL_IDS_HPP - +#endif // KOKKOS_TEST_GLOBAL_TO_LOCAL_IDS_HPP diff --git a/lib/kokkos/containers/performance_tests/TestHPX.cpp b/lib/kokkos/containers/performance_tests/TestHPX.cpp index 0f43377cee..48be466bfa 100644 --- a/lib/kokkos/containers/performance_tests/TestHPX.cpp +++ b/lib/kokkos/containers/performance_tests/TestHPX.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_HPX ) +#if defined(KOKKOS_ENABLE_HPX) #include @@ -61,70 +62,63 @@ #include #include - namespace Performance { class hpx : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::initialize(); - Kokkos::print_configuration( std::cout ); + Kokkos::print_configuration(std::cout); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( hpx, dynrankview_perf ) -{ +TEST_F(hpx, dynrankview_perf) { std::cout << "HPX" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 8192 ); + test_dynrankview_op_perf(8192); } -TEST_F( hpx, global_2_local) -{ +TEST_F(hpx, global_2_local) { std::cout << "HPX" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( hpx, unordered_map_performance_near) -{ +TEST_F(hpx, unordered_map_performance_near) { unsigned num_hpx = 4; std::ostringstream base_file_name; base_file_name << "hpx-" << num_hpx << "-near"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests( + base_file_name.str()); } -TEST_F( hpx, unordered_map_performance_far) -{ +TEST_F(hpx, unordered_map_performance_far) { unsigned num_hpx = 4; std::ostringstream base_file_name; base_file_name << "hpx-" << num_hpx << "-far"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests( + base_file_name.str()); } -TEST_F( hpx, scatter_view) -{ +TEST_F(hpx, scatter_view) { std::cout << "ScatterView data-duplicated test:\n"; Perf::test_scatter_view(10, 1000 * 1000); -//std::cout << "ScatterView atomics test:\n"; -//Perf::test_scatter_view(10, 1000 * 1000); + Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic>(10, + 1000 * 1000); + // std::cout << "ScatterView atomics test:\n"; + // Perf::test_scatter_view(10, 1000 * 1000); } -} // namespace test +} // namespace Performance #else void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTHPX_PREVENT_EMPTY_LINK_ERROR() {} #endif - diff --git a/lib/kokkos/containers/performance_tests/TestMain.cpp b/lib/kokkos/containers/performance_tests/TestMain.cpp index 217b01a57a..e3c8edb045 100644 --- a/lib/kokkos/containers/performance_tests/TestMain.cpp +++ b/lib/kokkos/containers/performance_tests/TestMain.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,6 @@ #include int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc,argv); + ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } - diff --git a/lib/kokkos/containers/performance_tests/TestOpenMP.cpp b/lib/kokkos/containers/performance_tests/TestOpenMP.cpp index e6218074ea..a9c8639ed4 100644 --- a/lib/kokkos/containers/performance_tests/TestOpenMP.cpp +++ b/lib/kokkos/containers/performance_tests/TestOpenMP.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_OPENMP ) +#if defined(KOKKOS_ENABLE_OPENMP) #include @@ -61,82 +62,72 @@ #include #include - namespace Performance { class openmp : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::initialize(); - Kokkos::OpenMP::print_configuration( std::cout ); + Kokkos::OpenMP::print_configuration(std::cout); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( openmp, dynrankview_perf ) -{ +TEST_F(openmp, dynrankview_perf) { std::cout << "OpenMP" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 8192 ); + test_dynrankview_op_perf(8192); } -TEST_F( openmp, global_2_local) -{ +TEST_F(openmp, global_2_local) { std::cout << "OpenMP" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( openmp, unordered_map_performance_near) -{ +TEST_F(openmp, unordered_map_performance_near) { unsigned num_openmp = 4; if (Kokkos::hwloc::available()) { num_openmp = Kokkos::hwloc::get_available_numa_count() * - Kokkos::hwloc::get_available_cores_per_numa() * - Kokkos::hwloc::get_available_threads_per_core(); - + Kokkos::hwloc::get_available_cores_per_numa() * + Kokkos::hwloc::get_available_threads_per_core(); } std::ostringstream base_file_name; base_file_name << "openmp-" << num_openmp << "-near"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -TEST_F( openmp, unordered_map_performance_far) -{ +TEST_F(openmp, unordered_map_performance_far) { unsigned num_openmp = 4; if (Kokkos::hwloc::available()) { num_openmp = Kokkos::hwloc::get_available_numa_count() * - Kokkos::hwloc::get_available_cores_per_numa() * - Kokkos::hwloc::get_available_threads_per_core(); - + Kokkos::hwloc::get_available_cores_per_numa() * + Kokkos::hwloc::get_available_threads_per_core(); } std::ostringstream base_file_name; base_file_name << "openmp-" << num_openmp << "-far"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -TEST_F( openmp, scatter_view) -{ +TEST_F(openmp, scatter_view) { std::cout << "ScatterView data-duplicated test:\n"; Perf::test_scatter_view(10, 1000 * 1000); -//std::cout << "ScatterView atomics test:\n"; -//Perf::test_scatter_view(10, 1000 * 1000); + Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic>(10, + 1000 * 1000); + // std::cout << "ScatterView atomics test:\n"; + // Perf::test_scatter_view(10, 1000 * 1000); } -} // namespace test +} // namespace Performance #else -void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTOPENMP_PREVENT_EMPTY_LINK_ERROR() {} +void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTOPENMP_PREVENT_EMPTY_LINK_ERROR() { +} #endif - diff --git a/lib/kokkos/containers/performance_tests/TestROCm.cpp b/lib/kokkos/containers/performance_tests/TestROCm.cpp index 3cf9f3bd14..55b770b49c 100644 --- a/lib/kokkos/containers/performance_tests/TestROCm.cpp +++ b/lib/kokkos/containers/performance_tests/TestROCm.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) #include #include @@ -66,15 +67,14 @@ namespace Performance { class rocm : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; Kokkos::HostSpace::execution_space::initialize(); - Kokkos::Experimental::ROCm::initialize( Kokkos::Experimental::ROCm::SelectDevice(0) ); + Kokkos::Experimental::ROCm::initialize( + Kokkos::Experimental::ROCm::SelectDevice(0)); } - static void TearDownTestCase() - { + static void TearDownTestCase() { Kokkos::Experimental::ROCm::finalize(); Kokkos::HostSpace::execution_space::finalize(); } @@ -97,17 +97,15 @@ TEST_F( rocm, global_2_local) } #endif -TEST_F( rocm, unordered_map_performance_near) -{ - Perf::run_performance_tests("rocm-near"); +TEST_F(rocm, unordered_map_performance_near) { + Perf::run_performance_tests("rocm-near"); } -TEST_F( rocm, unordered_map_performance_far) -{ - Perf::run_performance_tests("rocm-far"); +TEST_F(rocm, unordered_map_performance_far) { + Perf::run_performance_tests("rocm-far"); } -} +} // namespace Performance #else void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTROCM_PREVENT_EMPTY_LINK_ERROR() {} -#endif /* #if defined( KOKKOS_ENABLE_ROCM ) */ +#endif /* #if defined( KOKKOS_ENABLE_ROCM ) */ diff --git a/lib/kokkos/containers/performance_tests/TestScatterView.hpp b/lib/kokkos/containers/performance_tests/TestScatterView.hpp index bd9121bb82..3d4c57f3e2 100644 --- a/lib/kokkos/containers/performance_tests/TestScatterView.hpp +++ b/lib/kokkos/containers/performance_tests/TestScatterView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,67 +50,68 @@ namespace Perf { -template -void test_scatter_view(int m, int n) -{ - Kokkos::View original_view("original_view", n); +template +void test_scatter_view(int m, int n) { + Kokkos::View original_view("original_view", + n); { - auto scatter_view = Kokkos::Experimental::create_scatter_view - < Kokkos::Experimental::ScatterSum - , duplication - , contribution - > (original_view); + auto scatter_view = Kokkos::Experimental::create_scatter_view< + Kokkos::Experimental::ScatterSum, duplication, contribution>( + original_view); Kokkos::Experimental::UniqueToken< - ExecSpace, Kokkos::Experimental::UniqueTokenScope::Global> - unique_token{ExecSpace()}; - //auto internal_view = scatter_view.internal_view; + ExecSpace, Kokkos::Experimental::UniqueTokenScope::Global> + unique_token{ExecSpace()}; + // auto internal_view = scatter_view.internal_view; auto policy = Kokkos::RangePolicy(0, n); for (int foo = 0; foo < 5; ++foo) { - { - auto num_threads = unique_token.size(); - std::cout << "num_threads " << num_threads << '\n'; - Kokkos::View hand_coded_duplicate_view("hand_coded_duplicate", num_threads, n); - auto f2 = KOKKOS_LAMBDA(int i) { - auto thread_id = unique_token.acquire(); - for (int j = 0; j < 10; ++j) { - auto k = (i + j) % n; - hand_coded_duplicate_view(thread_id, k, 0) += 4.2; - hand_coded_duplicate_view(thread_id, k, 1) += 2.0; - hand_coded_duplicate_view(thread_id, k, 2) += 1.0; + { + auto num_threads = unique_token.size(); + std::cout << "num_threads " << num_threads << '\n'; + Kokkos::View + hand_coded_duplicate_view("hand_coded_duplicate", num_threads, n); + auto f2 = KOKKOS_LAMBDA(int i) { + auto thread_id = unique_token.acquire(); + for (int j = 0; j < 10; ++j) { + auto k = (i + j) % n; + hand_coded_duplicate_view(thread_id, k, 0) += 4.2; + hand_coded_duplicate_view(thread_id, k, 1) += 2.0; + hand_coded_duplicate_view(thread_id, k, 2) += 1.0; + } + }; + Kokkos::Timer timer; + timer.reset(); + for (int k = 0; k < m; ++k) { + Kokkos::parallel_for(policy, f2, + "hand_coded_duplicate_scatter_view_test"); } - }; - Kokkos::Timer timer; - timer.reset(); - for (int k = 0; k < m; ++k) { - Kokkos::parallel_for(policy, f2, "hand_coded_duplicate_scatter_view_test"); + Kokkos::fence(); + auto t = timer.seconds(); + std::cout << "hand-coded test took " << t << " seconds\n"; } - Kokkos::fence(); - auto t = timer.seconds(); - std::cout << "hand-coded test took " << t << " seconds\n"; - } - { - auto f = KOKKOS_LAMBDA(int i) { - auto scatter_access = scatter_view.access(); - for (int j = 0; j < 10; ++j) { - auto k = (i + j) % n; - scatter_access(k, 0) += 4.2; - scatter_access(k, 1) += 2.0; - scatter_access(k, 2) += 1.0; + { + auto f = KOKKOS_LAMBDA(int i) { + auto scatter_access = scatter_view.access(); + for (int j = 0; j < 10; ++j) { + auto k = (i + j) % n; + scatter_access(k, 0) += 4.2; + scatter_access(k, 1) += 2.0; + scatter_access(k, 2) += 1.0; + } + }; + Kokkos::Timer timer; + timer.reset(); + for (int k = 0; k < m; ++k) { + Kokkos::parallel_for(policy, f, "scatter_view_test"); } - }; - Kokkos::Timer timer; - timer.reset(); - for (int k = 0; k < m; ++k) { - Kokkos::parallel_for(policy, f, "scatter_view_test"); + Kokkos::fence(); + auto t = timer.seconds(); + std::cout << "test took " << t << " seconds\n"; } - Kokkos::fence(); - auto t = timer.seconds(); - std::cout << "test took " << t << " seconds\n"; } } - } } -} +} // namespace Perf #endif diff --git a/lib/kokkos/containers/performance_tests/TestThreads.cpp b/lib/kokkos/containers/performance_tests/TestThreads.cpp index 6a02e67b25..2f37404539 100644 --- a/lib/kokkos/containers/performance_tests/TestThreads.cpp +++ b/lib/kokkos/containers/performance_tests/TestThreads.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_THREADS ) +#if defined(KOKKOS_ENABLE_THREADS) #include @@ -65,9 +66,8 @@ namespace Performance { class threads : public ::testing::Test { -protected: - static void SetUpTestCase() - { + protected: + static void SetUpTestCase() { std::cout << std::setprecision(5) << std::scientific; unsigned num_threads = 4; @@ -76,66 +76,57 @@ protected: num_threads = Kokkos::hwloc::get_available_numa_count() * Kokkos::hwloc::get_available_cores_per_numa() * Kokkos::hwloc::get_available_threads_per_core(); - } std::cout << "Threads: " << num_threads << std::endl; - Kokkos::initialize( Kokkos::InitArguments(num_threads) ); + Kokkos::initialize(Kokkos::InitArguments(num_threads)); } - static void TearDownTestCase() - { - Kokkos::finalize(); - } + static void TearDownTestCase() { Kokkos::finalize(); } }; -TEST_F( threads, dynrankview_perf ) -{ +TEST_F(threads, dynrankview_perf) { std::cout << "Threads" << std::endl; std::cout << " DynRankView vs View: Initialization Only " << std::endl; - test_dynrankview_op_perf( 8192 ); + test_dynrankview_op_perf(8192); } -TEST_F( threads, global_2_local) -{ +TEST_F(threads, global_2_local) { std::cout << "Threads" << std::endl; std::cout << "size, create, generate, fill, find" << std::endl; - for (unsigned i=Performance::begin_id_size; i<=Performance::end_id_size; i *= Performance::id_step) + for (unsigned i = Performance::begin_id_size; i <= Performance::end_id_size; + i *= Performance::id_step) test_global_to_local_ids(i); } -TEST_F( threads, unordered_map_performance_near) -{ +TEST_F(threads, unordered_map_performance_near) { unsigned num_threads = 4; if (Kokkos::hwloc::available()) { num_threads = Kokkos::hwloc::get_available_numa_count() * Kokkos::hwloc::get_available_cores_per_numa() * Kokkos::hwloc::get_available_threads_per_core(); - } std::ostringstream base_file_name; base_file_name << "threads-" << num_threads << "-near"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -TEST_F( threads, unordered_map_performance_far) -{ +TEST_F(threads, unordered_map_performance_far) { unsigned num_threads = 4; if (Kokkos::hwloc::available()) { num_threads = Kokkos::hwloc::get_available_numa_count() * Kokkos::hwloc::get_available_cores_per_numa() * Kokkos::hwloc::get_available_threads_per_core(); - } std::ostringstream base_file_name; base_file_name << "threads-" << num_threads << "-far"; - Perf::run_performance_tests(base_file_name.str()); + Perf::run_performance_tests(base_file_name.str()); } -} // namespace Performance +} // namespace Performance #else -void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTTHREADS_PREVENT_EMPTY_LINK_ERROR() {} +void KOKKOS_CONTAINERS_PERFORMANCE_TESTS_TESTTHREADS_PREVENT_EMPTY_LINK_ERROR() { +} #endif - diff --git a/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp b/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp index 8d09281ed3..9057842340 100644 --- a/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp +++ b/lib/kokkos/containers/performance_tests/TestUnorderedMapPerformance.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -50,12 +51,10 @@ #include #include - namespace Perf { template -struct UnorderedMapTest -{ +struct UnorderedMapTest { typedef Device execution_space; typedef Kokkos::UnorderedMap map_type; typedef typename map_type::histogram_type histogram_type; @@ -68,22 +67,22 @@ struct UnorderedMapTest uint32_t capacity; uint32_t inserts; uint32_t collisions; - double seconds; + double seconds; map_type map; histogram_type histogram; - UnorderedMapTest( uint32_t arg_capacity, uint32_t arg_inserts, uint32_t arg_collisions) - : capacity(arg_capacity) - , inserts(arg_inserts) - , collisions(arg_collisions) - , seconds(0) - , map(capacity) - , histogram(map.get_histogram()) - { - Kokkos::Timer wall_clock ; + UnorderedMapTest(uint32_t arg_capacity, uint32_t arg_inserts, + uint32_t arg_collisions) + : capacity(arg_capacity), + inserts(arg_inserts), + collisions(arg_collisions), + seconds(0), + map(capacity), + histogram(map.get_histogram()) { + Kokkos::Timer wall_clock; wall_clock.reset(); - value_type v = {}; + value_type v = {}; int loop_count = 0; do { ++loop_count; @@ -92,81 +91,79 @@ struct UnorderedMapTest Kokkos::parallel_reduce(inserts, *this, v); if (v.failed_count > 0u) { - const uint32_t new_capacity = map.capacity() + ((map.capacity()*3ull)/20u) + v.failed_count/collisions ; - map.rehash( new_capacity ); + const uint32_t new_capacity = map.capacity() + + ((map.capacity() * 3ull) / 20u) + + v.failed_count / collisions; + map.rehash(new_capacity); } } while (v.failed_count > 0u); seconds = wall_clock.seconds(); - switch (loop_count) - { - case 1u: std::cout << " \033[0;32m" << loop_count << "\033[0m "; break; - case 2u: std::cout << " \033[1;31m" << loop_count << "\033[0m "; break; - default: std::cout << " \033[0;31m" << loop_count << "\033[0m "; break; + switch (loop_count) { + case 1u: std::cout << " \033[0;32m" << loop_count << "\033[0m "; break; + case 2u: std::cout << " \033[1;31m" << loop_count << "\033[0m "; break; + default: std::cout << " \033[0;31m" << loop_count << "\033[0m "; break; } - std::cout << std::setprecision(2) << std::fixed << std::setw(5) << (1e9*(seconds/(inserts))) << "; " << std::flush; + std::cout << std::setprecision(2) << std::fixed << std::setw(5) + << (1e9 * (seconds / (inserts))) << "; " << std::flush; histogram.calculate(); Device().fence(); } - void print(std::ostream & metrics_out, std::ostream & length_out, std::ostream & distance_out, std::ostream & block_distance_out) - { + void print(std::ostream& metrics_out, std::ostream& length_out, + std::ostream& distance_out, std::ostream& block_distance_out) { metrics_out << map.capacity() << " , "; - metrics_out << inserts/collisions << " , "; - metrics_out << (100.0 * inserts/collisions) / map.capacity() << " , "; + metrics_out << inserts / collisions << " , "; + metrics_out << (100.0 * inserts / collisions) / map.capacity() << " , "; metrics_out << inserts << " , "; metrics_out << (map.failed_insert() ? "true" : "false") << " , "; metrics_out << collisions << " , "; - metrics_out << 1e9*(seconds/inserts) << " , "; + metrics_out << 1e9 * (seconds / inserts) << " , "; metrics_out << seconds << std::endl; length_out << map.capacity() << " , "; - length_out << ((100.0 *inserts/collisions) / map.capacity()) << " , "; + length_out << ((100.0 * inserts / collisions) / map.capacity()) << " , "; length_out << collisions << " , "; histogram.print_length(length_out); distance_out << map.capacity() << " , "; - distance_out << ((100.0 *inserts/collisions) / map.capacity()) << " , "; + distance_out << ((100.0 * inserts / collisions) / map.capacity()) << " , "; distance_out << collisions << " , "; histogram.print_distance(distance_out); block_distance_out << map.capacity() << " , "; - block_distance_out << ((100.0 *inserts/collisions) / map.capacity()) << " , "; + block_distance_out << ((100.0 * inserts / collisions) / map.capacity()) + << " , "; block_distance_out << collisions << " , "; histogram.print_block_distance(block_distance_out); } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const - { + void init(value_type& v) const { v.failed_count = 0; - v.max_list = 0; + v.max_list = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { + void join(volatile value_type& dst, const volatile value_type& src) const { dst.failed_count += src.failed_count; dst.max_list = src.max_list < dst.max_list ? dst.max_list : src.max_list; } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { - const uint32_t key = Near ? i/collisions : i%(inserts/collisions); - typename map_type::insert_result result = map.insert(key,i); + void operator()(uint32_t i, value_type& v) const { + const uint32_t key = Near ? i / collisions : i % (inserts / collisions); + typename map_type::insert_result result = map.insert(key, i); v.failed_count += !result.failed() ? 0 : 1; - v.max_list = result.list_position() < v.max_list ? v.max_list : result.list_position(); + v.max_list = result.list_position() < v.max_list ? v.max_list + : result.list_position(); } - }; template -void run_performance_tests(std::string const & base_file_name) -{ +void run_performance_tests(std::string const& base_file_name) { #if 0 std::string metrics_file_name = base_file_name + std::string("-metrics.csv"); std::string length_file_name = base_file_name + std::string("-length.csv"); @@ -254,7 +251,6 @@ void run_performance_tests(std::string const & base_file_name) #endif } +} // namespace Perf -} // namespace Perf - -#endif //KOKKOS_TEST_UNORDERED_MAP_PERFORMANCE_HPP +#endif // KOKKOS_TEST_UNORDERED_MAP_PERFORMANCE_HPP diff --git a/lib/kokkos/containers/src/CMakeLists.txt b/lib/kokkos/containers/src/CMakeLists.txt index e68fcad5e9..0c9d24d641 100644 --- a/lib/kokkos/containers/src/CMakeLists.txt +++ b/lib/kokkos/containers/src/CMakeLists.txt @@ -1,47 +1,34 @@ - -TRIBITS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -#----------------------------------------------------------------------------- - -SET(TRILINOS_INCDIR ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}) - -if(KOKKOS_LEGACY_TRIBITS) - - SET(HEADERS "") - SET(SOURCES "") - - SET(HEADERS_IMPL "") - - FILE(GLOB HEADERS *.hpp) - FILE(GLOB HEADERS_IMPL impl/*.hpp) - FILE(GLOB SOURCES impl/*.cpp) - - INSTALL(FILES ${HEADERS_IMPL} DESTINATION ${TRILINOS_INCDIR}/impl/) - - TRIBITS_ADD_LIBRARY( - kokkoscontainers - HEADERS ${HEADERS} - NOINSTALLHEADERS ${HEADERS_IMPL} - SOURCES ${SOURCES} - DEPLIBS - ) - -else() - - INSTALL ( - DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${TRILINOS_INCDIR} - FILES_MATCHING PATTERN "*.hpp" - ) - - TRIBITS_ADD_LIBRARY( - kokkoscontainers - SOURCES ${KOKKOS_CONTAINERS_SRCS} - DEPLIBS - ) - -endif() -#----------------------------------------------------------------------------- + +KOKKOS_CONFIGURE_FILE(${PACKAGE_NAME}_config.h) + +#need these here for now +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) + +#----------------------------------------------------------------------------- + +SET(KOKKOS_CONTAINERS_SRCS) +APPEND_GLOB(KOKKOS_CONTAINERS_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp) + +INSTALL ( + DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${KOKKOS_HEADER_DIR} + FILES_MATCHING PATTERN "*.hpp" +) + +KOKKOS_ADD_LIBRARY( + kokkoscontainers + SOURCES ${KOKKOS_CONTAINERS_SRCS} +) + +SET_TARGET_PROPERTIES(kokkoscontainers PROPERTIES VERSION ${Kokkos_VERSION}) + +KOKKOS_LIB_INCLUDE_DIRECTORIES(kokkoscontainers + ${KOKKOS_TOP_BUILD_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) +KOKKOS_LINK_INTERNAL_LIBRARY(kokkoscontainers kokkoscore) + +#----------------------------------------------------------------------------- + diff --git a/lib/kokkos/containers/src/Kokkos_Bitset.hpp b/lib/kokkos/containers/src/Kokkos_Bitset.hpp index 4d78430fc6..3596c7653a 100644 --- a/lib/kokkos/containers/src/Kokkos_Bitset.hpp +++ b/lib/kokkos/containers/src/Kokkos_Bitset.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -53,27 +54,25 @@ namespace Kokkos { -template +template class Bitset; -template +template class ConstBitset; template -void deep_copy( Bitset & dst, Bitset const& src); +void deep_copy(Bitset& dst, Bitset const& src); template -void deep_copy( Bitset & dst, ConstBitset const& src); +void deep_copy(Bitset& dst, ConstBitset const& src); template -void deep_copy( ConstBitset & dst, ConstBitset const& src); - +void deep_copy(ConstBitset& dst, ConstBitset const& src); /// A thread safe view to a bitset template -class Bitset -{ -public: +class Bitset { + public: typedef Device execution_space; typedef unsigned size_type; @@ -81,98 +80,88 @@ public: enum { MOVE_HINT_BACKWARD = 2u }; enum { - BIT_SCAN_FORWARD_MOVE_HINT_FORWARD = 0u - , BIT_SCAN_REVERSE_MOVE_HINT_FORWARD = BIT_SCAN_REVERSE - , BIT_SCAN_FORWARD_MOVE_HINT_BACKWARD = MOVE_HINT_BACKWARD - , BIT_SCAN_REVERSE_MOVE_HINT_BACKWARD = BIT_SCAN_REVERSE | MOVE_HINT_BACKWARD + BIT_SCAN_FORWARD_MOVE_HINT_FORWARD = 0u, + BIT_SCAN_REVERSE_MOVE_HINT_FORWARD = BIT_SCAN_REVERSE, + BIT_SCAN_FORWARD_MOVE_HINT_BACKWARD = MOVE_HINT_BACKWARD, + BIT_SCAN_REVERSE_MOVE_HINT_BACKWARD = BIT_SCAN_REVERSE | MOVE_HINT_BACKWARD }; -private: - enum { block_size = static_cast(sizeof(unsigned)*CHAR_BIT) }; - enum { block_mask = block_size-1u }; + private: + enum { block_size = static_cast(sizeof(unsigned) * CHAR_BIT) }; + enum { block_mask = block_size - 1u }; enum { block_shift = Kokkos::Impl::integral_power_of_two(block_size) }; -public: - - + public: /// constructor /// arg_size := number of bit in set Bitset(unsigned arg_size = 0u) - : m_size(arg_size) - , m_last_block_mask(0u) - , m_blocks("Bitset", ((m_size + block_mask) >> block_shift) ) - { - for (int i=0, end = static_cast(m_size & block_mask); i < end; ++i) { + : m_size(arg_size), + m_last_block_mask(0u), + m_blocks("Bitset", ((m_size + block_mask) >> block_shift)) { + for (int i = 0, end = static_cast(m_size & block_mask); i < end; ++i) { m_last_block_mask |= 1u << i; } } KOKKOS_INLINE_FUNCTION - Bitset (const Bitset&) = default; + Bitset(const Bitset&) = default; KOKKOS_INLINE_FUNCTION - Bitset& operator= (const Bitset&) = default; + Bitset& operator=(const Bitset&) = default; KOKKOS_INLINE_FUNCTION - Bitset (Bitset&&) = default; + Bitset(Bitset&&) = default; KOKKOS_INLINE_FUNCTION - Bitset& operator= (Bitset&&) = default; - + Bitset& operator=(Bitset&&) = default; + KOKKOS_INLINE_FUNCTION - ~Bitset () = default; + ~Bitset() = default; /// number of bits in the set /// can be call from the host or the device KOKKOS_FORCEINLINE_FUNCTION - unsigned size() const - { return m_size; } + unsigned size() const { return m_size; } /// number of bits which are set to 1 /// can only be called from the host - unsigned count() const - { - Impl::BitsetCount< Bitset > f(*this); + unsigned count() const { + Impl::BitsetCount > f(*this); return f.apply(); } /// set all bits to 1 /// can only be called from the host - void set() - { - Kokkos::deep_copy(m_blocks, ~0u ); + void set() { + Kokkos::deep_copy(m_blocks, ~0u); if (m_last_block_mask) { - //clear the unused bits in the last block - typedef Kokkos::Impl::DeepCopy< typename execution_space::memory_space, Kokkos::HostSpace > raw_deep_copy; - raw_deep_copy( m_blocks.data() + (m_blocks.extent(0) -1u), &m_last_block_mask, sizeof(unsigned)); + // clear the unused bits in the last block + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(m_blocks.data() + (m_blocks.extent(0) - 1u), + &m_last_block_mask, sizeof(unsigned)); } } /// set all bits to 0 /// can only be called from the host - void reset() - { - Kokkos::deep_copy(m_blocks, 0u ); - } + void reset() { Kokkos::deep_copy(m_blocks, 0u); } /// set all bits to 0 /// can only be called from the host - void clear() - { - Kokkos::deep_copy(m_blocks, 0u ); - } + void clear() { Kokkos::deep_copy(m_blocks, 0u); } /// set i'th bit to 1 /// can only be called from the device KOKKOS_FORCEINLINE_FUNCTION - bool set( unsigned i ) const - { - if ( i < m_size ) { - unsigned * block_ptr = &m_blocks[ i >> block_shift ]; - const unsigned mask = 1u << static_cast( i & block_mask ); + bool set(unsigned i) const { + if (i < m_size) { + unsigned* block_ptr = &m_blocks[i >> block_shift]; + const unsigned mask = 1u << static_cast(i & block_mask); - return !( atomic_fetch_or( block_ptr, mask ) & mask ); + return !(atomic_fetch_or(block_ptr, mask) & mask); } return false; } @@ -180,13 +169,12 @@ public: /// set i'th bit to 0 /// can only be called from the device KOKKOS_FORCEINLINE_FUNCTION - bool reset( unsigned i ) const - { - if ( i < m_size ) { - unsigned * block_ptr = &m_blocks[ i >> block_shift ]; - const unsigned mask = 1u << static_cast( i & block_mask ); + bool reset(unsigned i) const { + if (i < m_size) { + unsigned* block_ptr = &m_blocks[i >> block_shift]; + const unsigned mask = 1u << static_cast(i & block_mask); - return atomic_fetch_and( block_ptr, ~mask ) & mask; + return atomic_fetch_and(block_ptr, ~mask) & mask; } return false; } @@ -194,11 +182,10 @@ public: /// return true if the i'th bit set to 1 /// can only be called from the device KOKKOS_FORCEINLINE_FUNCTION - bool test( unsigned i ) const - { - if ( i < m_size ) { - const unsigned block = volatile_load(&m_blocks[ i >> block_shift ]); - const unsigned mask = 1u << static_cast( i & block_mask ); + bool test(unsigned i) const { + if (i < m_size) { + const unsigned block = volatile_load(&m_blocks[i >> block_shift]); + const unsigned mask = 1u << static_cast(i & block_mask); return block & mask; } return false; @@ -208,90 +195,93 @@ public: /// returns the max number of times those functions should be call /// when searching for an available bit KOKKOS_FORCEINLINE_FUNCTION - unsigned max_hint() const - { - return m_blocks.extent(0); - } + unsigned max_hint() const { return m_blocks.extent(0); } /// find a bit set to 1 near the hint - /// returns a pair< bool, unsigned> where if result.first is true then result.second is the bit found - /// and if result.first is false the result.second is a new hint + /// returns a pair< bool, unsigned> where if result.first is true then + /// result.second is the bit found and if result.first is false the + /// result.second is a new hint KOKKOS_INLINE_FUNCTION - Kokkos::pair find_any_set_near( unsigned hint , unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD ) const - { - const unsigned block_idx = (hint >> block_shift) < m_blocks.extent(0) ? (hint >> block_shift) : 0; + Kokkos::pair find_any_set_near( + unsigned hint, + unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD) const { + const unsigned block_idx = + (hint >> block_shift) < m_blocks.extent(0) ? (hint >> block_shift) : 0; const unsigned offset = hint & block_mask; - unsigned block = volatile_load(&m_blocks[ block_idx ]); - block = !m_last_block_mask || (block_idx < (m_blocks.extent(0)-1)) ? block : block & m_last_block_mask ; + unsigned block = volatile_load(&m_blocks[block_idx]); + block = !m_last_block_mask || (block_idx < (m_blocks.extent(0) - 1)) + ? block + : block & m_last_block_mask; return find_any_helper(block_idx, offset, block, scan_direction); } /// find a bit set to 0 near the hint - /// returns a pair< bool, unsigned> where if result.first is true then result.second is the bit found - /// and if result.first is false the result.second is a new hint + /// returns a pair< bool, unsigned> where if result.first is true then + /// result.second is the bit found and if result.first is false the + /// result.second is a new hint KOKKOS_INLINE_FUNCTION - Kokkos::pair find_any_unset_near( unsigned hint , unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD ) const - { + Kokkos::pair find_any_unset_near( + unsigned hint, + unsigned scan_direction = BIT_SCAN_FORWARD_MOVE_HINT_FORWARD) const { const unsigned block_idx = hint >> block_shift; - const unsigned offset = hint & block_mask; - unsigned block = volatile_load(&m_blocks[ block_idx ]); - block = !m_last_block_mask || (block_idx < (m_blocks.extent(0)-1) ) ? ~block : ~block & m_last_block_mask ; + const unsigned offset = hint & block_mask; + unsigned block = volatile_load(&m_blocks[block_idx]); + block = !m_last_block_mask || (block_idx < (m_blocks.extent(0) - 1)) + ? ~block + : ~block & m_last_block_mask; return find_any_helper(block_idx, offset, block, scan_direction); } -private: - + private: KOKKOS_FORCEINLINE_FUNCTION - Kokkos::pair find_any_helper(unsigned block_idx, unsigned offset, unsigned block, unsigned scan_direction) const - { - Kokkos::pair result( block > 0u, 0); + Kokkos::pair find_any_helper(unsigned block_idx, + unsigned offset, unsigned block, + unsigned scan_direction) const { + Kokkos::pair result(block > 0u, 0); if (!result.first) { - result.second = update_hint( block_idx, offset, scan_direction ); - } - else { - result.second = scan_block( (block_idx << block_shift) - , offset - , block - , scan_direction - ); + result.second = update_hint(block_idx, offset, scan_direction); + } else { + result.second = + scan_block((block_idx << block_shift), offset, block, scan_direction); } return result; } - KOKKOS_FORCEINLINE_FUNCTION - unsigned scan_block(unsigned block_start, int offset, unsigned block, unsigned scan_direction ) const - { - offset = !(scan_direction & BIT_SCAN_REVERSE) ? offset : (offset + block_mask) & block_mask; + unsigned scan_block(unsigned block_start, int offset, unsigned block, + unsigned scan_direction) const { + offset = !(scan_direction & BIT_SCAN_REVERSE) + ? offset + : (offset + block_mask) & block_mask; block = Impl::rotate_right(block, offset); - return ((( !(scan_direction & BIT_SCAN_REVERSE) ? - Impl::bit_scan_forward(block) : - ::Kokkos::log2(block) - ) + offset - ) & block_mask - ) + block_start; + return (((!(scan_direction & BIT_SCAN_REVERSE) + ? Impl::bit_scan_forward(block) + : ::Kokkos::log2(block)) + + offset) & + block_mask) + + block_start; } KOKKOS_FORCEINLINE_FUNCTION - unsigned update_hint( long long block_idx, unsigned offset, unsigned scan_direction ) const - { + unsigned update_hint(long long block_idx, unsigned offset, + unsigned scan_direction) const { block_idx += scan_direction & MOVE_HINT_BACKWARD ? -1 : 1; block_idx = block_idx >= 0 ? block_idx : m_blocks.extent(0) - 1; - block_idx = block_idx < static_cast(m_blocks.extent(0)) ? block_idx : 0; + block_idx = + block_idx < static_cast(m_blocks.extent(0)) ? block_idx : 0; - return static_cast(block_idx)*block_size + offset; + return static_cast(block_idx) * block_size + offset; } -private: - + private: unsigned m_size; unsigned m_last_block_mask; - View< unsigned *, execution_space, MemoryTraits > m_blocks; + View > m_blocks; -private: + private: template friend class Bitset; @@ -302,87 +292,72 @@ private: friend struct Impl::BitsetCount; template - friend void deep_copy( Bitset & dst, Bitset const& src); + friend void deep_copy(Bitset& dst, Bitset const& src); template - friend void deep_copy( Bitset & dst, ConstBitset const& src); + friend void deep_copy(Bitset& dst, + ConstBitset const& src); }; /// a thread-safe view to a const bitset /// i.e. can only test bits template -class ConstBitset -{ -public: +class ConstBitset { + public: typedef Device execution_space; typedef unsigned size_type; -private: - enum { block_size = static_cast(sizeof(unsigned)*CHAR_BIT) }; - enum { block_mask = block_size -1u }; + private: + enum { block_size = static_cast(sizeof(unsigned) * CHAR_BIT) }; + enum { block_mask = block_size - 1u }; enum { block_shift = Kokkos::Impl::integral_power_of_two(block_size) }; -public: - ConstBitset() - : m_size (0) - {} + public: + ConstBitset() : m_size(0) {} ConstBitset(Bitset const& rhs) - : m_size(rhs.m_size) - , m_blocks(rhs.m_blocks) - {} + : m_size(rhs.m_size), m_blocks(rhs.m_blocks) {} ConstBitset(ConstBitset const& rhs) - : m_size( rhs.m_size ) - , m_blocks( rhs.m_blocks ) - {} + : m_size(rhs.m_size), m_blocks(rhs.m_blocks) {} - ConstBitset & operator = (Bitset const & rhs) - { - this->m_size = rhs.m_size; + ConstBitset& operator=(Bitset const& rhs) { + this->m_size = rhs.m_size; this->m_blocks = rhs.m_blocks; return *this; } - ConstBitset & operator = (ConstBitset const & rhs) - { - this->m_size = rhs.m_size; + ConstBitset& operator=(ConstBitset const& rhs) { + this->m_size = rhs.m_size; this->m_blocks = rhs.m_blocks; return *this; } - KOKKOS_FORCEINLINE_FUNCTION - unsigned size() const - { - return m_size; - } + unsigned size() const { return m_size; } - unsigned count() const - { - Impl::BitsetCount< ConstBitset > f(*this); + unsigned count() const { + Impl::BitsetCount > f(*this); return f.apply(); } KOKKOS_FORCEINLINE_FUNCTION - bool test( unsigned i ) const - { - if ( i < m_size ) { - const unsigned block = m_blocks[ i >> block_shift ]; - const unsigned mask = 1u << static_cast( i & block_mask ); + bool test(unsigned i) const { + if (i < m_size) { + const unsigned block = m_blocks[i >> block_shift]; + const unsigned mask = 1u << static_cast(i & block_mask); return block & mask; } return false; } -private: - + private: unsigned m_size; - View< const unsigned *, execution_space, MemoryTraits > m_blocks; + View > m_blocks; -private: + private: template friend class ConstBitset; @@ -390,47 +365,56 @@ private: friend struct Impl::BitsetCount; template - friend void deep_copy( Bitset & dst, ConstBitset const& src); + friend void deep_copy(Bitset& dst, + ConstBitset const& src); template - friend void deep_copy( ConstBitset & dst, ConstBitset const& src); + friend void deep_copy(ConstBitset& dst, + ConstBitset const& src); }; - template -void deep_copy( Bitset & dst, Bitset const& src) -{ +void deep_copy(Bitset& dst, Bitset const& src) { if (dst.size() != src.size()) { - throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!"); + throw std::runtime_error( + "Error: Cannot deep_copy bitsets of different sizes!"); } - typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy; - raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), sizeof(unsigned)*src.m_blocks.extent(0)); + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), + sizeof(unsigned) * src.m_blocks.extent(0)); } template -void deep_copy( Bitset & dst, ConstBitset const& src) -{ +void deep_copy(Bitset& dst, ConstBitset const& src) { if (dst.size() != src.size()) { - throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!"); + throw std::runtime_error( + "Error: Cannot deep_copy bitsets of different sizes!"); } - typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy; - raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), sizeof(unsigned)*src.m_blocks.extent(0)); + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), + sizeof(unsigned) * src.m_blocks.extent(0)); } template -void deep_copy( ConstBitset & dst, ConstBitset const& src) -{ +void deep_copy(ConstBitset& dst, ConstBitset const& src) { if (dst.size() != src.size()) { - throw std::runtime_error("Error: Cannot deep_copy bitsets of different sizes!"); + throw std::runtime_error( + "Error: Cannot deep_copy bitsets of different sizes!"); } - typedef Kokkos::Impl::DeepCopy< typename DstDevice::memory_space, typename SrcDevice::memory_space > raw_deep_copy; - raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), sizeof(unsigned)*src.m_blocks.extent(0)); + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; + raw_deep_copy(dst.m_blocks.data(), src.m_blocks.data(), + sizeof(unsigned) * src.m_blocks.extent(0)); } -} // namespace Kokkos - -#endif //KOKKOS_BITSET_HPP +} // namespace Kokkos +#endif // KOKKOS_BITSET_HPP diff --git a/lib/kokkos/containers/src/Kokkos_DualView.hpp b/lib/kokkos/containers/src/Kokkos_DualView.hpp index d9b14d67a2..d8a3ebc1ae 100644 --- a/lib/kokkos/containers/src/Kokkos_DualView.hpp +++ b/lib/kokkos/containers/src/Kokkos_DualView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -90,47 +91,41 @@ namespace Kokkos { * behavior. Please see the documentation of Kokkos::View for * examples. The default suffices for most users. */ -template< class DataType , - class Arg1Type = void , - class Arg2Type = void , +template -class DualView : public ViewTraits< DataType , Arg1Type , Arg2Type, Arg3Type > -{ -template< class , class , class , class > friend class DualView ; -public: +class DualView : public ViewTraits { + template + friend class DualView; + + public: //! \name Typedefs for device types and various Kokkos::View specializations. //@{ - typedef ViewTraits< DataType , Arg1Type , Arg2Type, Arg3Type > traits ; + typedef ViewTraits traits; //! The Kokkos Host Device type; - typedef typename traits::host_mirror_space host_mirror_space ; + typedef typename traits::host_mirror_space host_mirror_space; //! The type of a Kokkos::View on the device. - typedef View< typename traits::data_type , - Arg1Type , - Arg2Type , - Arg3Type > t_dev ; + typedef View t_dev; /// \typedef t_host /// \brief The type of a Kokkos::View host mirror of \c t_dev. - typedef typename t_dev::HostMirror t_host ; + typedef typename t_dev::HostMirror t_host; //! The type of a const View on the device. //! The type of a Kokkos::View on the device. - typedef View< typename traits::const_data_type , - Arg1Type , - Arg2Type , - Arg3Type > t_dev_const ; + typedef View + t_dev_const; /// \typedef t_host_const /// \brief The type of a const View host mirror of \c t_dev_const. typedef typename t_dev_const::HostMirror t_host_const; //! The type of a const, random-access View on the device. - typedef View< typename traits::const_data_type , - typename traits::array_layout , - typename traits::device_type , - Kokkos::MemoryTraits > t_dev_const_randomread ; + typedef View > + t_dev_const_randomread; /// \typedef t_host_const_randomread /// \brief The type of a const, random-access View host mirror of @@ -138,39 +133,36 @@ public: typedef typename t_dev_const_randomread::HostMirror t_host_const_randomread; //! The type of an unmanaged View on the device. - typedef View< typename traits::data_type , - typename traits::array_layout , - typename traits::device_type , - MemoryUnmanaged> t_dev_um; + typedef View + t_dev_um; //! The type of an unmanaged View host mirror of \c t_dev_um. - typedef View< typename t_host::data_type , - typename t_host::array_layout , - typename t_host::device_type , - MemoryUnmanaged> t_host_um; + typedef View + t_host_um; //! The type of a const unmanaged View on the device. - typedef View< typename traits::const_data_type , - typename traits::array_layout , - typename traits::device_type , - MemoryUnmanaged> t_dev_const_um; + typedef View + t_dev_const_um; //! The type of a const unmanaged View host mirror of \c t_dev_const_um. - typedef View t_host_const_um; + typedef View + t_host_const_um; //! The type of a const, random-access View on the device. - typedef View< typename t_host::const_data_type , - typename t_host::array_layout , - typename t_host::device_type , - Kokkos::MemoryTraits > t_dev_const_randomread_um ; + typedef View > + t_dev_const_randomread_um; /// \typedef t_host_const_randomread /// \brief The type of a const, random-access View host mirror of /// \c t_dev_const_randomread. - typedef typename t_dev_const_randomread::HostMirror t_host_const_randomread_um; + typedef + typename t_dev_const_randomread::HostMirror t_host_const_randomread_um; //@} //! \name The two View instances. @@ -184,18 +176,20 @@ public: //@{ #ifndef KOKKOS_ENABLE_DEPRECATED_CODE -protected: + protected: // modified_flags[0] -> host // modified_flags[1] -> device - typedef View t_modified_flags; + typedef View t_modified_flags; t_modified_flags modified_flags; -public: + public: #else - typedef View t_modified_flags; - typedef View t_modified_flag; + typedef View + t_modified_flags; + typedef View + t_modified_flag; t_modified_flags modified_flags; - t_modified_flag modified_host,modified_device; + t_modified_flag modified_host, modified_device; #endif //@} @@ -208,11 +202,11 @@ public: /// default constructors. The "modified" flags are both initialized /// to "unmodified." #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - DualView () = default; + DualView() = default; #else - DualView ():modified_flags (t_modified_flags("DualView::modified_flags")) { - modified_host = t_modified_flag(modified_flags,0); - modified_device = t_modified_flag(modified_flags,1); + DualView() : modified_flags(t_modified_flags("DualView::modified_flags")) { + modified_host = t_modified_flag(modified_flags, 0); + modified_device = t_modified_flag(modified_flags, 1); } #endif @@ -225,52 +219,52 @@ public: /// View objects. For example, if the View has three dimensions, /// the first three integer arguments will be nonzero, and you may /// omit the integer arguments that follow. - DualView (const std::string& label, - const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) - : d_view (label, n0, n1, n2, n3, n4, n5, n6, n7) - , h_view (create_mirror_view (d_view)) // without UVM, host View mirrors - , modified_flags (t_modified_flags("DualView::modified_flags")) - { + DualView(const std::string& label, + const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) + : d_view(label, n0, n1, n2, n3, n4, n5, n6, n7), + h_view(create_mirror_view(d_view)) // without UVM, host View mirrors + , + modified_flags(t_modified_flags("DualView::modified_flags")) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - modified_host = t_modified_flag(modified_flags,0); - modified_device = t_modified_flag(modified_flags,1); + modified_host = t_modified_flag(modified_flags, 0); + modified_device = t_modified_flag(modified_flags, 1); #endif } //! Copy constructor (shallow copy) - template - DualView (const DualView& src) : - d_view (src.d_view), - h_view (src.h_view), - modified_flags (src.modified_flags) + template + DualView(const DualView& src) + : d_view(src.d_view), + h_view(src.h_view), + modified_flags(src.modified_flags) #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - , modified_host(src.modified_host) - , modified_device(src.modified_device) + , + modified_host(src.modified_host), + modified_device(src.modified_device) #endif - {} + { + } //! Subview constructor - template< class SD, class S1 , class S2 , class S3 - , class Arg0 , class ... Args > - DualView( const DualView & src - , const Arg0 & arg0 - , Args ... args - ) - : d_view( Kokkos::subview( src.d_view , arg0 , args ... ) ) - , h_view( Kokkos::subview( src.h_view , arg0 , args ... ) ) - , modified_flags (src.modified_flags) + template + DualView(const DualView& src, const Arg0& arg0, Args... args) + : d_view(Kokkos::subview(src.d_view, arg0, args...)), + h_view(Kokkos::subview(src.h_view, arg0, args...)), + modified_flags(src.modified_flags) #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - , modified_host(src.modified_host) - , modified_device(src.modified_device) + , + modified_host(src.modified_host), + modified_device(src.modified_device) #endif - {} + { + } /// \brief Create DualView from existing device and host View objects. /// @@ -282,34 +276,34 @@ public: /// /// \param d_view_ Device View /// \param h_view_ Host View (must have type t_host = t_dev::HostMirror) - DualView (const t_dev& d_view_, const t_host& h_view_) : - d_view (d_view_), - h_view (h_view_), - modified_flags (t_modified_flags("DualView::modified_flags")) - { - if ( int(d_view.rank) != int(h_view.rank) || - d_view.extent(0) != h_view.extent(0) || - d_view.extent(1) != h_view.extent(1) || - d_view.extent(2) != h_view.extent(2) || - d_view.extent(3) != h_view.extent(3) || - d_view.extent(4) != h_view.extent(4) || - d_view.extent(5) != h_view.extent(5) || - d_view.extent(6) != h_view.extent(6) || - d_view.extent(7) != h_view.extent(7) || - d_view.stride_0() != h_view.stride_0() || - d_view.stride_1() != h_view.stride_1() || - d_view.stride_2() != h_view.stride_2() || - d_view.stride_3() != h_view.stride_3() || - d_view.stride_4() != h_view.stride_4() || - d_view.stride_5() != h_view.stride_5() || - d_view.stride_6() != h_view.stride_6() || - d_view.stride_7() != h_view.stride_7() || - d_view.span() != h_view.span() ) { - Kokkos::Impl::throw_runtime_exception("DualView constructed with incompatible views"); + DualView(const t_dev& d_view_, const t_host& h_view_) + : d_view(d_view_), + h_view(h_view_), + modified_flags(t_modified_flags("DualView::modified_flags")) { + if (int(d_view.rank) != int(h_view.rank) || + d_view.extent(0) != h_view.extent(0) || + d_view.extent(1) != h_view.extent(1) || + d_view.extent(2) != h_view.extent(2) || + d_view.extent(3) != h_view.extent(3) || + d_view.extent(4) != h_view.extent(4) || + d_view.extent(5) != h_view.extent(5) || + d_view.extent(6) != h_view.extent(6) || + d_view.extent(7) != h_view.extent(7) || + d_view.stride_0() != h_view.stride_0() || + d_view.stride_1() != h_view.stride_1() || + d_view.stride_2() != h_view.stride_2() || + d_view.stride_3() != h_view.stride_3() || + d_view.stride_4() != h_view.stride_4() || + d_view.stride_5() != h_view.stride_5() || + d_view.stride_6() != h_view.stride_6() || + d_view.stride_7() != h_view.stride_7() || + d_view.span() != h_view.span()) { + Kokkos::Impl::throw_runtime_exception( + "DualView constructed with incompatible views"); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - modified_host = t_modified_flag(modified_flags,0); - modified_device = t_modified_flag(modified_flags,1); + modified_host = t_modified_flag(modified_flags, 0); + modified_device = t_modified_flag(modified_flags, 1); #endif } @@ -326,119 +320,133 @@ public: /// /// For example, suppose you create a DualView on Cuda, like this: /// \code - /// typedef Kokkos::DualView dual_view_type; - /// dual_view_type DV ("my dual view", 100); - /// \endcode - /// If you want to get the CUDA device View, do this: - /// \code - /// typename dual_view_type::t_dev cudaView = DV.view (); - /// \endcode - /// and if you want to get the host mirror of that View, do this: - /// \code - /// typedef typename Kokkos::HostSpace::execution_space host_device_type; - /// typename dual_view_type::t_host hostView = DV.view (); - /// \endcode - template< class Device > - KOKKOS_INLINE_FUNCTION - const typename Impl::if_c< - std::is_same::value, - t_dev, - t_host>::type& view () const - { - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - constexpr bool device_is_memspace = std::is_same::value; - constexpr bool device_is_execspace = std::is_same::value; - constexpr bool device_exec_is_t_dev_exec = std::is_same::value; - constexpr bool device_mem_is_t_dev_mem = std::is_same::value; - constexpr bool device_exec_is_t_host_exec = std::is_same::value; - constexpr bool device_mem_is_t_host_mem = std::is_same::value; - constexpr bool device_is_t_host_device = std::is_same::value; - constexpr bool device_is_t_dev_device = std::is_same::value; + /// typedef Kokkos::DualView + /// dual_view_type; dual_view_type DV ("my dual view", 100); \endcode If you + /// want to get the CUDA device View, do this: \code typename + /// dual_view_type::t_dev cudaView = DV.view (); \endcode and if + /// you want to get the host mirror of that View, do this: \code typedef + /// typename Kokkos::HostSpace::execution_space host_device_type; typename + /// dual_view_type::t_host hostView = DV.view (); \endcode + template + KOKKOS_INLINE_FUNCTION const typename Impl::if_c< + std::is_same::value, + t_dev, t_host>::type& + view() const { +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE + constexpr bool device_is_memspace = + std::is_same::value; + constexpr bool device_is_execspace = + std::is_same::value; + constexpr bool device_exec_is_t_dev_exec = + std::is_same::value; + constexpr bool device_mem_is_t_dev_mem = + std::is_same::value; + constexpr bool device_exec_is_t_host_exec = + std::is_same::value; + constexpr bool device_mem_is_t_host_mem = + std::is_same::value; + constexpr bool device_is_t_host_device = + std::is_same::value; + constexpr bool device_is_t_dev_device = + std::is_same::value; static_assert( device_is_t_dev_device || device_is_t_host_device || - (device_is_memspace && (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ) || - (device_is_execspace && (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) ) || - ( - (!device_is_execspace && !device_is_memspace) && ( - (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || - (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) - ) - ) - , - "Template parameter to .view() must exactly match one of the DualView's device types or one of the execution or memory spaces"); - #endif - - return Impl::if_c< - std::is_same< - typename t_dev::memory_space, - typename Device::memory_space>::value, - t_dev, - t_host >::select (d_view , h_view); + (device_is_memspace && + (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) || + (device_is_execspace && + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) || + ((!device_is_execspace && !device_is_memspace) && + ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))), + "Template parameter to .view() must exactly match one of the " + "DualView's device types or one of the execution or memory spaces"); +#endif + + return Impl::if_c::value, + t_dev, t_host>::select(d_view, h_view); } KOKKOS_INLINE_FUNCTION - t_host view_host() const { - return h_view; - } + t_host view_host() const { return h_view; } KOKKOS_INLINE_FUNCTION - t_dev view_device() const { - return d_view; - } + t_dev view_device() const { return d_view; } - template + template static int get_device_side() { - constexpr bool device_is_memspace = std::is_same::value; - constexpr bool device_is_execspace = std::is_same::value; - constexpr bool device_exec_is_t_dev_exec = std::is_same::value; - constexpr bool device_mem_is_t_dev_mem = std::is_same::value; - constexpr bool device_exec_is_t_host_exec = std::is_same::value; - constexpr bool device_mem_is_t_host_mem = std::is_same::value; - constexpr bool device_is_t_host_device = std::is_same::value; - constexpr bool device_is_t_dev_device = std::is_same::value; - - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE + constexpr bool device_is_memspace = + std::is_same::value; + constexpr bool device_is_execspace = + std::is_same::value; + constexpr bool device_exec_is_t_dev_exec = + std::is_same::value; + constexpr bool device_mem_is_t_dev_mem = + std::is_same::value; + constexpr bool device_exec_is_t_host_exec = + std::is_same::value; + constexpr bool device_mem_is_t_host_mem = + std::is_same::value; + constexpr bool device_is_t_host_device = + std::is_same::value; + constexpr bool device_is_t_dev_device = + std::is_same::value; + +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE static_assert( device_is_t_dev_device || device_is_t_host_device || - (device_is_memspace && (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) ) || - (device_is_execspace && (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) ) || - ( - (!device_is_execspace && !device_is_memspace) && ( - (device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || - (device_exec_is_t_dev_exec || device_exec_is_t_host_exec) - ) - ) - , - "Template parameter to .sync() must exactly match one of the DualView's device types or one of the execution or memory spaces"); - #endif + (device_is_memspace && + (device_mem_is_t_dev_mem || device_mem_is_t_host_mem)) || + (device_is_execspace && + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec)) || + ((!device_is_execspace && !device_is_memspace) && + ((device_mem_is_t_dev_mem || device_mem_is_t_host_mem) || + (device_exec_is_t_dev_exec || device_exec_is_t_host_exec))), + "Template parameter to .sync() must exactly match one of the " + "DualView's device types or one of the execution or memory spaces"); +#endif - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE int dev = -1; - #else +#else int dev = 0; - #endif - if(device_is_t_dev_device) dev = 1; - else if(device_is_t_host_device) dev = 0; +#endif + if (device_is_t_dev_device) + dev = 1; + else if (device_is_t_host_device) + dev = 0; else { - if(device_is_memspace) { - if(device_mem_is_t_dev_mem) dev = 1; - if(device_mem_is_t_host_mem) dev = 0; - if(device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; + if (device_is_memspace) { + if (device_mem_is_t_dev_mem) dev = 1; + if (device_mem_is_t_host_mem) dev = 0; + if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; } - if(device_is_execspace) { - if(device_exec_is_t_dev_exec) dev = 1; - if(device_exec_is_t_host_exec) dev = 0; - if(device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; + if (device_is_execspace) { + if (device_exec_is_t_dev_exec) dev = 1; + if (device_exec_is_t_host_exec) dev = 0; + if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; } - if(!device_is_execspace && !device_is_memspace) { - if(device_mem_is_t_dev_mem) dev = 1; - if(device_mem_is_t_host_mem) dev = 0; - if(device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; - if(device_exec_is_t_dev_exec) dev = 1; - if(device_exec_is_t_host_exec) dev = 0; - if(device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; + if (!device_is_execspace && !device_is_memspace) { + if (device_mem_is_t_dev_mem) dev = 1; + if (device_mem_is_t_host_mem) dev = 0; + if (device_mem_is_t_host_mem && device_mem_is_t_dev_mem) dev = -1; + if (device_exec_is_t_dev_exec) dev = 1; + if (device_exec_is_t_host_exec) dev = 0; + if (device_exec_is_t_host_exec && device_exec_is_t_dev_exec) dev = -1; } } return dev; @@ -461,88 +469,94 @@ public: /// the data in either View. You must manually mark modified data /// as modified, by calling the modify() method with the /// appropriate template parameter. - template - void sync( const typename Impl::enable_if< - ( std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value) || - ( std::is_same< Device , int>::value) - , int >::type& = 0) - { - if(modified_flags.data()==NULL) return; + template + void sync(const typename Impl::enable_if< + (std::is_same::value) || + (std::is_same::value), + int>::type& = 0) { + if (modified_flags.data() == NULL) return; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) { - deep_copy (d_view, h_view); + deep_copy(d_view, h_view); modified_flags(0) = modified_flags(1) = 0; } } - if (dev == 0) { // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) { - deep_copy (h_view, d_view); + deep_copy(h_view, d_view); modified_flags(0) = modified_flags(1) = 0; } } - if(std::is_same::value) { + if (std::is_same::value) { typename t_dev::execution_space().fence(); typename t_host::execution_space().fence(); } } - template - void sync ( const typename Impl::enable_if< - ( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) || - ( std::is_same< Device , int>::value) - , int >::type& = 0 ) - { - if(modified_flags.data()==NULL) return; + template + void sync(const typename Impl::enable_if< + (!std::is_same::value) || + (std::is_same::value), + int>::type& = 0) { + if (modified_flags.data() == NULL) return; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) { - Impl::throw_runtime_exception("Calling sync on a DualView with a const datatype."); + Impl::throw_runtime_exception( + "Calling sync on a DualView with a const datatype."); } } - if (dev == 0){ // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) { - Impl::throw_runtime_exception("Calling sync on a DualView with a const datatype."); + Impl::throw_runtime_exception( + "Calling sync on a DualView with a const datatype."); } } } void sync_host() { - if( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) - Impl::throw_runtime_exception("Calling sync_host on a DualView with a const datatype."); - if(modified_flags.data()==NULL) return; - if(modified_flags(1) > modified_flags(0)) { - deep_copy (h_view, d_view); + if (!std::is_same::value) + Impl::throw_runtime_exception( + "Calling sync_host on a DualView with a const datatype."); + if (modified_flags.data() == NULL) return; + if (modified_flags(1) > modified_flags(0)) { + deep_copy(h_view, d_view); modified_flags(1) = modified_flags(0) = 0; } } void sync_device() { - if( ! std::is_same< typename traits::data_type , typename traits::non_const_data_type>::value ) - Impl::throw_runtime_exception("Calling sync_device on a DualView with a const datatype."); - if(modified_flags.data()==NULL) return; - if(modified_flags(0) > modified_flags(1)) { - deep_copy (d_view, h_view); + if (!std::is_same::value) + Impl::throw_runtime_exception( + "Calling sync_device on a DualView with a const datatype."); + if (modified_flags.data() == NULL) return; + if (modified_flags(0) > modified_flags(1)) { + deep_copy(d_view, h_view); modified_flags(1) = modified_flags(0) = 0; } } - template - bool need_sync() const - { - if(modified_flags.data()==NULL) return false; + template + bool need_sync() const { + if (modified_flags.data() == NULL) return false; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type if ((modified_flags(0) > 0) && (modified_flags(0) >= modified_flags(1))) { return true; } } - if (dev == 0){ // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type if ((modified_flags(1) > 0) && (modified_flags(1) >= modified_flags(0))) { return true; } @@ -551,13 +565,13 @@ public: } inline bool need_sync_host() const { - if(modified_flags.data()==NULL) return false; - return modified_flags(0) - void modify () { - if(modified_flags.data()==NULL) return; + template + void modify() { + if (modified_flags.data() == NULL) return; int dev = get_device_side(); - if (dev == 1) { // if Device is the same as DualView's device type + if (dev == 1) { // if Device is the same as DualView's device type // Increment the device's modified count. - modified_flags(1) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; + modified_flags(1) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; } - if (dev == 0) { // hopefully Device is the same as DualView's host type + if (dev == 0) { // hopefully Device is the same as DualView's host type // Increment the host's modified count. - modified_flags(0) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; + modified_flags(0) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; } #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK @@ -594,10 +612,12 @@ public: } inline void modify_host() { - if(modified_flags.data()!=NULL) { - modified_flags(0) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; - #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK + if (modified_flags.data() != NULL) { + modified_flags(0) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; +#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK if (modified_flags(0) && modified_flags(1)) { std::string msg = "Kokkos::DualView::modify_host ERROR: "; msg += "Concurrent modification of host and device views "; @@ -606,15 +626,17 @@ public: msg += "\"\n"; Kokkos::abort(msg.c_str()); } - #endif +#endif } } inline void modify_device() { - if(modified_flags.data()!=NULL) { - modified_flags(1) = (modified_flags(1) > modified_flags(0) ? - modified_flags(1) : modified_flags(0)) + 1; - #ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK + if (modified_flags.data() != NULL) { + modified_flags(1) = + (modified_flags(1) > modified_flags(0) ? modified_flags(1) + : modified_flags(0)) + + 1; +#ifdef KOKKOS_ENABLE_DEBUG_DUALVIEW_MODIFY_CHECK if (modified_flags(0) && modified_flags(1)) { std::string msg = "Kokkos::DualView::modify_device ERROR: "; msg += "Concurrent modification of host and device views "; @@ -623,12 +645,12 @@ public: msg += "\"\n"; Kokkos::abort(msg.c_str()); } - #endif +#endif } } inline void clear_sync_state() { - if(modified_flags.data()!=NULL) + if (modified_flags.data() != NULL) modified_flags(1) = modified_flags(0) = 0; } @@ -641,75 +663,72 @@ public: /// This discards any existing contents of the objects, and resets /// their modified flags. It does not copy the old contents /// of either View into the new View objects. - void realloc( const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) { - ::Kokkos::realloc(d_view,n0,n1,n2,n3,n4,n5,n6,n7); - h_view = create_mirror_view( d_view ); - - /* Reset dirty flags */ - if(modified_flags.data()==NULL) { - modified_flags = t_modified_flags("DualView::modified_flags"); - } else - modified_flags(1) = modified_flags(0) = 0; + void realloc(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + ::Kokkos::realloc(d_view, n0, n1, n2, n3, n4, n5, n6, n7); + h_view = create_mirror_view(d_view); + + /* Reset dirty flags */ + if (modified_flags.data() == NULL) { + modified_flags = t_modified_flags("DualView::modified_flags"); + } else + modified_flags(1) = modified_flags(0) = 0; } /// \brief Resize both views, copying old contents into new if necessary. /// /// This method only copies the old contents into the new View /// objects for the device which was last marked as modified. - void resize( const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) { - if(modified_flags.data()==NULL) { - modified_flags = t_modified_flags("DualView::modified_flags"); - } - if(modified_flags(1) >= modified_flags(0)) { - /* Resize on Device */ - ::Kokkos::resize(d_view,n0,n1,n2,n3,n4,n5,n6,n7); - h_view = create_mirror_view( d_view ); - - /* Mark Device copy as modified */ - modified_flags(1) = modified_flags(1)+1; - - } else { - /* Realloc on Device */ - - ::Kokkos::realloc(d_view,n0,n1,n2,n3,n4,n5,n6,n7); - - const bool sizeMismatch = ( h_view.extent(0) != n0 ) || - ( h_view.extent(1) != n1 ) || - ( h_view.extent(2) != n2 ) || - ( h_view.extent(3) != n3 ) || - ( h_view.extent(4) != n4 ) || - ( h_view.extent(5) != n5 ) || - ( h_view.extent(6) != n6 ) || - ( h_view.extent(7) != n7 ); - if ( sizeMismatch ) - ::Kokkos::resize(h_view,n0,n1,n2,n3,n4,n5,n6,n7); - - t_host temp_view = create_mirror_view( d_view ); - - /* Remap on Host */ - Kokkos::deep_copy( temp_view , h_view ); - - h_view = temp_view; - - d_view = create_mirror_view( typename t_dev::execution_space(), h_view ); - - /* Mark Host copy as modified */ - modified_flags(0) = modified_flags(0)+1; - } + void resize(const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + if (modified_flags.data() == NULL) { + modified_flags = t_modified_flags("DualView::modified_flags"); + } + if (modified_flags(1) >= modified_flags(0)) { + /* Resize on Device */ + ::Kokkos::resize(d_view, n0, n1, n2, n3, n4, n5, n6, n7); + h_view = create_mirror_view(d_view); + + /* Mark Device copy as modified */ + modified_flags(1) = modified_flags(1) + 1; + + } else { + /* Realloc on Device */ + + ::Kokkos::realloc(d_view, n0, n1, n2, n3, n4, n5, n6, n7); + + const bool sizeMismatch = + (h_view.extent(0) != n0) || (h_view.extent(1) != n1) || + (h_view.extent(2) != n2) || (h_view.extent(3) != n3) || + (h_view.extent(4) != n4) || (h_view.extent(5) != n5) || + (h_view.extent(6) != n6) || (h_view.extent(7) != n7); + if (sizeMismatch) + ::Kokkos::resize(h_view, n0, n1, n2, n3, n4, n5, n6, n7); + + t_host temp_view = create_mirror_view(d_view); + + /* Remap on Host */ + Kokkos::deep_copy(temp_view, h_view); + + h_view = temp_view; + + d_view = create_mirror_view(typename t_dev::execution_space(), h_view); + + /* Mark Host copy as modified */ + modified_flags(0) = modified_flags(0) + 1; + } } //@} @@ -718,37 +737,35 @@ public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE //! The allocation size (same as Kokkos::View::capacity). - size_t capacity() const { - return d_view.span(); - } + size_t capacity() const { return d_view.span(); } #endif //! The allocation size (same as Kokkos::View::span). - KOKKOS_INLINE_FUNCTION constexpr size_t span() const { - return d_view.span(); - } + KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return d_view.span(); } - KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { - return d_view.span_is_contiguous(); + KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { + return d_view.span_is_contiguous(); } //! Get stride(s) for each dimension. - template< typename iType> + template void stride(iType* stride_) const { d_view.stride(stride_); } - template< typename iType > - KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - extent( const iType & r ) const - { return d_view.extent(r); } + template + KOKKOS_INLINE_FUNCTION constexpr + typename std::enable_if::value, size_t>::type + extent(const iType& r) const { + return d_view.extent(r); + } - template< typename iType > - KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , int >::type - extent_int( const iType & r ) const - { return static_cast(d_view.extent(r)); } + template + KOKKOS_INLINE_FUNCTION constexpr + typename std::enable_if::value, int>::type + extent_int(const iType& r) const { + return static_cast(d_view.extent(r)); + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /* Deprecate all 'dimension' functions in favor of @@ -756,27 +773,27 @@ public: */ /* \brief return size of dimension 0 */ - size_t dimension_0() const {return d_view.extent(0);} + size_t dimension_0() const { return d_view.extent(0); } /* \brief return size of dimension 1 */ - size_t dimension_1() const {return d_view.extent(1);} + size_t dimension_1() const { return d_view.extent(1); } /* \brief return size of dimension 2 */ - size_t dimension_2() const {return d_view.extent(2);} + size_t dimension_2() const { return d_view.extent(2); } /* \brief return size of dimension 3 */ - size_t dimension_3() const {return d_view.extent(3);} + size_t dimension_3() const { return d_view.extent(3); } /* \brief return size of dimension 4 */ - size_t dimension_4() const {return d_view.extent(4);} + size_t dimension_4() const { return d_view.extent(4); } /* \brief return size of dimension 5 */ - size_t dimension_5() const {return d_view.extent(5);} + size_t dimension_5() const { return d_view.extent(5); } /* \brief return size of dimension 6 */ - size_t dimension_6() const {return d_view.extent(6);} + size_t dimension_6() const { return d_view.extent(6); } /* \brief return size of dimension 7 */ - size_t dimension_7() const {return d_view.extent(7);} + size_t dimension_7() const { return d_view.extent(7); } #endif //@} }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -787,32 +804,24 @@ public: namespace Kokkos { namespace Impl { -template< class D, class A1, class A2, class A3, class ... Args > +template struct DualViewSubview { + typedef typename Kokkos::Impl::ViewMapping< + void, Kokkos::ViewTraits, Args...>::traits_type dst_traits; - typedef typename Kokkos::Impl::ViewMapping - < void - , Kokkos::ViewTraits< D, A1, A2, A3 > - , Args ... - >::traits_type dst_traits ; - - typedef Kokkos::DualView - < typename dst_traits::data_type - , typename dst_traits::array_layout - , typename dst_traits::device_type - , typename dst_traits::memory_traits - > type ; + typedef Kokkos::DualView< + typename dst_traits::data_type, typename dst_traits::array_layout, + typename dst_traits::device_type, typename dst_traits::memory_traits> + type; }; } /* namespace Impl */ - -template< class D , class A1 , class A2 , class A3 , class ... Args > -typename Impl::DualViewSubview::type -subview( const DualView & src , Args ... args ) -{ - return typename - Impl::DualViewSubview::type( src , args ... ); +template +typename Impl::DualViewSubview::type subview( + const DualView& src, Args... args) { + return typename Impl::DualViewSubview::type(src, + args...); } } /* namespace Kokkos */ @@ -826,40 +835,35 @@ namespace Kokkos { // Partial specialization of Kokkos::deep_copy() for DualView objects. // -template< class DT , class DL , class DD , class DM , - class ST , class SL , class SD , class SM > -void -deep_copy (DualView dst, // trust me, this must not be a reference - const DualView& src ) -{ - if ( src.need_sync_device() ) { - deep_copy (dst.h_view, src.h_view); +template +void deep_copy( + DualView dst, // trust me, this must not be a reference + const DualView& src) { + if (src.need_sync_device()) { + deep_copy(dst.h_view, src.h_view); dst.modify_host(); - } - else { - deep_copy (dst.d_view, src.d_view); + } else { + deep_copy(dst.d_view, src.d_view); dst.modify_device(); - } + } } -template< class ExecutionSpace , - class DT , class DL , class DD , class DM , - class ST , class SL , class SD , class SM > -void -deep_copy (const ExecutionSpace& exec , - DualView dst, // trust me, this must not be a reference - const DualView& src ) -{ - if ( src.need_sync_device() ) { - deep_copy (exec, dst.h_view, src.h_view); +template +void deep_copy( + const ExecutionSpace& exec, + DualView dst, // trust me, this must not be a reference + const DualView& src) { + if (src.need_sync_device()) { + deep_copy(exec, dst.h_view, src.h_view); dst.modify_host(); } else { - deep_copy (exec, dst.d_view, src.d_view); + deep_copy(exec, dst.d_view, src.d_view); dst.modify_device(); } } -} // namespace Kokkos +} // namespace Kokkos #endif - diff --git a/lib/kokkos/containers/src/Kokkos_DynRankView.hpp b/lib/kokkos/containers/src/Kokkos_DynRankView.hpp index d1e6704a57..0ceb9d5d39 100644 --- a/lib/kokkos/containers/src/Kokkos_DynRankView.hpp +++ b/lib/kokkos/containers/src/Kokkos_DynRankView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -56,255 +57,240 @@ namespace Kokkos { -template< typename DataType , class ... Properties > -class DynRankView; //forward declare +template +class DynRankView; // forward declare namespace Impl { template struct DynRankDimTraits { - - enum : size_t{unspecified = KOKKOS_INVALID_INDEX}; + enum : size_t { unspecified = KOKKOS_INVALID_INDEX }; // Compute the rank of the view from the nonzero dimension arguments. KOKKOS_INLINE_FUNCTION - static size_t computeRank( const size_t N0 - , const size_t N1 - , const size_t N2 - , const size_t N3 - , const size_t N4 - , const size_t N5 - , const size_t N6 - , const size_t /* N7 */) - { - return - ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified && N2 == unspecified && N1 == unspecified && N0 == unspecified) ? 0 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified && N2 == unspecified && N1 == unspecified) ? 1 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified && N2 == unspecified) ? 2 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified && N3 == unspecified) ? 3 - : ( (N6 == unspecified && N5 == unspecified && N4 == unspecified) ? 4 - : ( (N6 == unspecified && N5 == unspecified) ? 5 - : ( (N6 == unspecified) ? 6 - : 7 ) ) ) ) ) ) ); + static size_t computeRank(const size_t N0, const size_t N1, const size_t N2, + const size_t N3, const size_t N4, const size_t N5, + const size_t N6, const size_t /* N7 */) { + return ( + (N6 == unspecified && N5 == unspecified && N4 == unspecified && + N3 == unspecified && N2 == unspecified && N1 == unspecified && + N0 == unspecified) + ? 0 + : ((N6 == unspecified && N5 == unspecified && N4 == unspecified && + N3 == unspecified && N2 == unspecified && N1 == unspecified) + ? 1 + : ((N6 == unspecified && N5 == unspecified && + N4 == unspecified && N3 == unspecified && + N2 == unspecified) + ? 2 + : ((N6 == unspecified && N5 == unspecified && + N4 == unspecified && N3 == unspecified) + ? 3 + : ((N6 == unspecified && N5 == unspecified && + N4 == unspecified) + ? 4 + : ((N6 == unspecified && + N5 == unspecified) + ? 5 + : ((N6 == unspecified) + ? 6 + : 7))))))); } // Compute the rank of the view from the nonzero layout arguments. template - KOKKOS_INLINE_FUNCTION - static size_t computeRank( const Layout& layout ) - { - return computeRank( layout.dimension[0] - , layout.dimension[1] - , layout.dimension[2] - , layout.dimension[3] - , layout.dimension[4] - , layout.dimension[5] - , layout.dimension[6] - , layout.dimension[7] ); + KOKKOS_INLINE_FUNCTION static size_t computeRank(const Layout& layout) { + return computeRank(layout.dimension[0], layout.dimension[1], + layout.dimension[2], layout.dimension[3], + layout.dimension[4], layout.dimension[5], + layout.dimension[6], layout.dimension[7]); } // Extra overload to match that for specialize types v2 - template - KOKKOS_INLINE_FUNCTION - static size_t computeRank( const Kokkos::Impl::ViewCtorProp& /* prop */, const Layout& layout ) - { + template + KOKKOS_INLINE_FUNCTION static size_t computeRank( + const Kokkos::Impl::ViewCtorProp& /* prop */, + const Layout& layout) { return computeRank(layout); } // Create the layout for the rank-7 view. // Non-strided Layout template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value || std::is_same::value) , Layout >::type createLayout( const Layout& layout ) - { - return Layout( layout.dimension[0] != unspecified ? layout.dimension[0] : 1 - , layout.dimension[1] != unspecified ? layout.dimension[1] : 1 - , layout.dimension[2] != unspecified ? layout.dimension[2] : 1 - , layout.dimension[3] != unspecified ? layout.dimension[3] : 1 - , layout.dimension[4] != unspecified ? layout.dimension[4] : 1 - , layout.dimension[5] != unspecified ? layout.dimension[5] : 1 - , layout.dimension[6] != unspecified ? layout.dimension[6] : 1 - , layout.dimension[7] != unspecified ? layout.dimension[7] : 1 - ); + KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value || + std::is_same::value), + Layout>::type + createLayout(const Layout& layout) { + return Layout(layout.dimension[0] != unspecified ? layout.dimension[0] : 1, + layout.dimension[1] != unspecified ? layout.dimension[1] : 1, + layout.dimension[2] != unspecified ? layout.dimension[2] : 1, + layout.dimension[3] != unspecified ? layout.dimension[3] : 1, + layout.dimension[4] != unspecified ? layout.dimension[4] : 1, + layout.dimension[5] != unspecified ? layout.dimension[5] : 1, + layout.dimension[6] != unspecified ? layout.dimension[6] : 1, + layout.dimension[7] != unspecified ? layout.dimension[7] : 1); } // LayoutStride template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value) , Layout>::type createLayout( const Layout& layout ) - { - return Layout( layout.dimension[0] != unspecified ? layout.dimension[0] : 1 - , layout.stride[0] - , layout.dimension[1] != unspecified ? layout.dimension[1] : 1 - , layout.stride[1] - , layout.dimension[2] != unspecified ? layout.dimension[2] : 1 - , layout.stride[2] - , layout.dimension[3] != unspecified ? layout.dimension[3] : 1 - , layout.stride[3] - , layout.dimension[4] != unspecified ? layout.dimension[4] : 1 - , layout.stride[4] - , layout.dimension[5] != unspecified ? layout.dimension[5] : 1 - , layout.stride[5] - , layout.dimension[6] != unspecified ? layout.dimension[6] : 1 - , layout.stride[6] - , layout.dimension[7] != unspecified ? layout.dimension[7] : 1 - , layout.stride[7] - ); + KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value), Layout>::type + createLayout(const Layout& layout) { + return Layout(layout.dimension[0] != unspecified ? layout.dimension[0] : 1, + layout.stride[0], + layout.dimension[1] != unspecified ? layout.dimension[1] : 1, + layout.stride[1], + layout.dimension[2] != unspecified ? layout.dimension[2] : 1, + layout.stride[2], + layout.dimension[3] != unspecified ? layout.dimension[3] : 1, + layout.stride[3], + layout.dimension[4] != unspecified ? layout.dimension[4] : 1, + layout.stride[4], + layout.dimension[5] != unspecified ? layout.dimension[5] : 1, + layout.stride[5], + layout.dimension[6] != unspecified ? layout.dimension[6] : 1, + layout.stride[6], + layout.dimension[7] != unspecified ? layout.dimension[7] : 1, + layout.stride[7]); } // Extra overload to match that for specialize types - template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value || std::is_same::value || std::is_same::value) , typename Traits::array_layout >::type createLayout( const Kokkos::Impl::ViewCtorProp& /* prop */, const typename Traits::array_layout& layout ) - { - return createLayout( layout ); + template + KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value || + std::is_same::value || + std::is_same::value), + typename Traits::array_layout>::type + createLayout(const Kokkos::Impl::ViewCtorProp& /* prop */, + const typename Traits::array_layout& layout) { + return createLayout(layout); } // Create a view from the given dimension arguments. // This is only necessary because the shmem constructor doesn't take a layout. - // NDE shmem View's are not compatible with the added view_alloc value_type / fad_dim deduction functionality + // NDE shmem View's are not compatible with the added view_alloc value_type + // / fad_dim deduction functionality template - static ViewType createView( const ViewArg& arg - , const size_t N0 - , const size_t N1 - , const size_t N2 - , const size_t N3 - , const size_t N4 - , const size_t N5 - , const size_t N6 - , const size_t N7 ) - { - return ViewType( arg - , N0 != unspecified ? N0 : 1 - , N1 != unspecified ? N1 : 1 - , N2 != unspecified ? N2 : 1 - , N3 != unspecified ? N3 : 1 - , N4 != unspecified ? N4 : 1 - , N5 != unspecified ? N5 : 1 - , N6 != unspecified ? N6 : 1 - , N7 != unspecified ? N7 : 1 ); + static ViewType createView(const ViewArg& arg, const size_t N0, + const size_t N1, const size_t N2, const size_t N3, + const size_t N4, const size_t N5, const size_t N6, + const size_t N7) { + return ViewType(arg, N0 != unspecified ? N0 : 1, N1 != unspecified ? N1 : 1, + N2 != unspecified ? N2 : 1, N3 != unspecified ? N3 : 1, + N4 != unspecified ? N4 : 1, N5 != unspecified ? N5 : 1, + N6 != unspecified ? N6 : 1, N7 != unspecified ? N7 : 1); } }; - // Non-strided Layout - template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value || std::is_same::value) && std::is_integral::value , Layout >::type - reconstructLayout( const Layout& layout , iType dynrank ) - { - return Layout( dynrank > 0 ? layout.dimension[0] :KOKKOS_INVALID_INDEX - , dynrank > 1 ? layout.dimension[1] :KOKKOS_INVALID_INDEX - , dynrank > 2 ? layout.dimension[2] :KOKKOS_INVALID_INDEX - , dynrank > 3 ? layout.dimension[3] :KOKKOS_INVALID_INDEX - , dynrank > 4 ? layout.dimension[4] :KOKKOS_INVALID_INDEX - , dynrank > 5 ? layout.dimension[5] :KOKKOS_INVALID_INDEX - , dynrank > 6 ? layout.dimension[6] :KOKKOS_INVALID_INDEX - , dynrank > 7 ? layout.dimension[7] :KOKKOS_INVALID_INDEX - ); - } - - // LayoutStride - template - KOKKOS_INLINE_FUNCTION - static typename std::enable_if< (std::is_same::value) && std::is_integral::value , Layout >::type - reconstructLayout( const Layout& layout , iType dynrank ) - { - return Layout( dynrank > 0 ? layout.dimension[0] :KOKKOS_INVALID_INDEX - , dynrank > 0 ? layout.stride[0] : (0) - , dynrank > 1 ? layout.dimension[1] :KOKKOS_INVALID_INDEX - , dynrank > 1 ? layout.stride[1] : (0) - , dynrank > 2 ? layout.dimension[2] :KOKKOS_INVALID_INDEX - , dynrank > 2 ? layout.stride[2] : (0) - , dynrank > 3 ? layout.dimension[3] :KOKKOS_INVALID_INDEX - , dynrank > 3 ? layout.stride[3] : (0) - , dynrank > 4 ? layout.dimension[4] :KOKKOS_INVALID_INDEX - , dynrank > 4 ? layout.stride[4] : (0) - , dynrank > 5 ? layout.dimension[5] :KOKKOS_INVALID_INDEX - , dynrank > 5 ? layout.stride[5] : (0) - , dynrank > 6 ? layout.dimension[6] :KOKKOS_INVALID_INDEX - , dynrank > 6 ? layout.stride[6] : (0) - , dynrank > 7 ? layout.dimension[7] :KOKKOS_INVALID_INDEX - , dynrank > 7 ? layout.stride[7] : (0) - ); - } +// Non-strided Layout +template +KOKKOS_INLINE_FUNCTION static + typename std::enable_if<(std::is_same::value || + std::is_same::value) && + std::is_integral::value, + Layout>::type + reconstructLayout(const Layout& layout, iType dynrank) { + return Layout(dynrank > 0 ? layout.dimension[0] : KOKKOS_INVALID_INDEX, + dynrank > 1 ? layout.dimension[1] : KOKKOS_INVALID_INDEX, + dynrank > 2 ? layout.dimension[2] : KOKKOS_INVALID_INDEX, + dynrank > 3 ? layout.dimension[3] : KOKKOS_INVALID_INDEX, + dynrank > 4 ? layout.dimension[4] : KOKKOS_INVALID_INDEX, + dynrank > 5 ? layout.dimension[5] : KOKKOS_INVALID_INDEX, + dynrank > 6 ? layout.dimension[6] : KOKKOS_INVALID_INDEX, + dynrank > 7 ? layout.dimension[7] : KOKKOS_INVALID_INDEX); +} +// LayoutStride +template +KOKKOS_INLINE_FUNCTION static typename std::enable_if< + (std::is_same::value) && + std::is_integral::value, + Layout>::type +reconstructLayout(const Layout& layout, iType dynrank) { + return Layout(dynrank > 0 ? layout.dimension[0] : KOKKOS_INVALID_INDEX, + dynrank > 0 ? layout.stride[0] : (0), + dynrank > 1 ? layout.dimension[1] : KOKKOS_INVALID_INDEX, + dynrank > 1 ? layout.stride[1] : (0), + dynrank > 2 ? layout.dimension[2] : KOKKOS_INVALID_INDEX, + dynrank > 2 ? layout.stride[2] : (0), + dynrank > 3 ? layout.dimension[3] : KOKKOS_INVALID_INDEX, + dynrank > 3 ? layout.stride[3] : (0), + dynrank > 4 ? layout.dimension[4] : KOKKOS_INVALID_INDEX, + dynrank > 4 ? layout.stride[4] : (0), + dynrank > 5 ? layout.dimension[5] : KOKKOS_INVALID_INDEX, + dynrank > 5 ? layout.stride[5] : (0), + dynrank > 6 ? layout.dimension[6] : KOKKOS_INVALID_INDEX, + dynrank > 6 ? layout.stride[6] : (0), + dynrank > 7 ? layout.dimension[7] : KOKKOS_INVALID_INDEX, + dynrank > 7 ? layout.stride[7] : (0)); +} /** \brief Debug bounds-checking routines */ // Enhanced debug checking - most infrastructure matches that of functions in // Kokkos_ViewMapping; additional checks for extra arguments beyond rank are 0 -template< unsigned , typename iType0 , class MapType > -KOKKOS_INLINE_FUNCTION -bool dyn_rank_view_verify_operator_bounds( const iType0 & , const MapType & ) -{ return true ; } - -template< unsigned R , typename iType0 , class MapType , typename iType1 , class ... Args > -KOKKOS_INLINE_FUNCTION -bool dyn_rank_view_verify_operator_bounds - ( const iType0 & rank - , const MapType & map - , const iType1 & i - , Args ... args - ) -{ - if ( static_cast(R) < rank ) { - return ( size_t(i) < map.extent(R) ) - && dyn_rank_view_verify_operator_bounds( rank , map , args ... ); - } - else if ( i != 0 ) { - printf("DynRankView Debug Bounds Checking Error: at rank %u\n Extra arguments beyond the rank must be zero \n",R); - return ( false ) - && dyn_rank_view_verify_operator_bounds( rank , map , args ... ); - } - else { - return ( true ) - && dyn_rank_view_verify_operator_bounds( rank , map , args ... ); +template +KOKKOS_INLINE_FUNCTION bool dyn_rank_view_verify_operator_bounds( + const iType0&, const MapType&) { + return true; +} + +template +KOKKOS_INLINE_FUNCTION bool dyn_rank_view_verify_operator_bounds( + const iType0& rank, const MapType& map, const iType1& i, Args... args) { + if (static_cast(R) < rank) { + return (size_t(i) < map.extent(R)) && + dyn_rank_view_verify_operator_bounds(rank, map, args...); + } else if (i != 0) { + printf( + "DynRankView Debug Bounds Checking Error: at rank %u\n Extra " + "arguments beyond the rank must be zero \n", + R); + return (false) && + dyn_rank_view_verify_operator_bounds(rank, map, args...); + } else { + return (true) && + dyn_rank_view_verify_operator_bounds(rank, map, args...); } } -template< unsigned , class MapType > -inline -void dyn_rank_view_error_operator_bounds( char * , int , const MapType & ) -{} - -template< unsigned R , class MapType , class iType , class ... Args > -inline -void dyn_rank_view_error_operator_bounds - ( char * buf - , int len - , const MapType & map - , const iType & i - , Args ... args - ) -{ - const int n = - snprintf(buf,len," %ld < %ld %c" - , static_cast(i) - , static_cast( map.extent(R) ) - , ( sizeof...(Args) ? ',' : ')' ) - ); - dyn_rank_view_error_operator_bounds(buf+n,len-n,map,args...); +template +inline void dyn_rank_view_error_operator_bounds(char*, int, const MapType&) {} + +template +inline void dyn_rank_view_error_operator_bounds(char* buf, int len, + const MapType& map, + const iType& i, Args... args) { + const int n = snprintf( + buf, len, " %ld < %ld %c", static_cast(i), + static_cast(map.extent(R)), (sizeof...(Args) ? ',' : ')')); + dyn_rank_view_error_operator_bounds(buf + n, len - n, map, args...); } // op_rank = rank of the operator version that was called -template< typename MemorySpace - , typename iType0 , typename iType1 , class MapType , class ... Args > -KOKKOS_INLINE_FUNCTION -void dyn_rank_view_verify_operator_bounds - ( const iType0 & op_rank , const iType1 & rank - , const Kokkos::Impl::SharedAllocationTracker & tracker - , const MapType & map , Args ... args ) -{ - if ( static_cast(rank) > op_rank ) { - Kokkos::abort( "DynRankView Bounds Checking Error: Need at least rank arguments to the operator()" ); - } - - if ( ! dyn_rank_view_verify_operator_bounds<0>( rank , map , args ... ) ) { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) +template +KOKKOS_INLINE_FUNCTION void dyn_rank_view_verify_operator_bounds( + const iType0& op_rank, const iType1& rank, + const Kokkos::Impl::SharedAllocationTracker& tracker, const MapType& map, + Args... args) { + if (static_cast(rank) > op_rank) { + Kokkos::abort( + "DynRankView Bounds Checking Error: Need at least rank arguments to " + "the operator()"); + } + + if (!dyn_rank_view_verify_operator_bounds<0>(rank, map, args...)) { +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) enum { LEN = 1024 }; - char buffer[ LEN ]; + char buffer[LEN]; const std::string label = tracker.template get_label(); - int n = snprintf(buffer,LEN,"DynRankView bounds error of view %s (", label.c_str()); - dyn_rank_view_error_operator_bounds<0>( buffer + n , LEN - n , map , args ... ); + int n = snprintf(buffer, LEN, "DynRankView bounds error of view %s (", + label.c_str()); + dyn_rank_view_error_operator_bounds<0>(buffer + n, LEN - n, map, args...); Kokkos::Impl::throw_runtime_exception(std::string(buffer)); #else Kokkos::abort("DynRankView bounds error"); @@ -312,86 +298,84 @@ void dyn_rank_view_verify_operator_bounds } } - /** \brief Assign compatible default mappings */ struct ViewToDynRankViewTag {}; -} // namespace Impl +} // namespace Impl namespace Impl { -template< class DstTraits , class SrcTraits > -class ViewMapping< DstTraits , SrcTraits , - typename std::enable_if<( - std::is_same< typename DstTraits::memory_space , typename SrcTraits::memory_space >::value - && - std::is_same< typename DstTraits::specialize , void >::value - && - std::is_same< typename SrcTraits::specialize , void >::value - && - ( - std::is_same< typename DstTraits::array_layout , typename SrcTraits::array_layout >::value - || - ( - ( - std::is_same< typename DstTraits::array_layout , Kokkos::LayoutLeft >::value || - std::is_same< typename DstTraits::array_layout , Kokkos::LayoutRight >::value || - std::is_same< typename DstTraits::array_layout , Kokkos::LayoutStride >::value - ) - && - ( - std::is_same< typename SrcTraits::array_layout , Kokkos::LayoutLeft >::value || - std::is_same< typename SrcTraits::array_layout , Kokkos::LayoutRight >::value || - std::is_same< typename SrcTraits::array_layout , Kokkos::LayoutStride >::value - ) - ) - ) - ) , Kokkos::Impl::ViewToDynRankViewTag >::type > -{ -private: - - enum { is_assignable_value_type = - std::is_same< typename DstTraits::value_type - , typename SrcTraits::value_type >::value || - std::is_same< typename DstTraits::value_type - , typename SrcTraits::const_value_type >::value }; - - enum { is_assignable_layout = - std::is_same< typename DstTraits::array_layout - , typename SrcTraits::array_layout >::value || - std::is_same< typename DstTraits::array_layout - , Kokkos::LayoutStride >::value - }; +template +class ViewMapping< + DstTraits, SrcTraits, + typename std::enable_if< + (std::is_same::value && + std::is_same::value && + std::is_same::value && + (std::is_same::value || + ((std::is_same::value || + std::is_same::value || + std::is_same::value) && + (std::is_same::value || + std::is_same::value || + std::is_same::value)))), + Kokkos::Impl::ViewToDynRankViewTag>::type> { + private: + enum { + is_assignable_value_type = + std::is_same::value || + std::is_same::value + }; -public: + enum { + is_assignable_layout = + std::is_same::value || + std::is_same::value + }; - enum { is_assignable = is_assignable_value_type && - is_assignable_layout }; + public: + enum { is_assignable = is_assignable_value_type && is_assignable_layout }; - typedef ViewMapping< DstTraits , typename DstTraits::specialize > DstType ; - typedef ViewMapping< SrcTraits , typename SrcTraits::specialize > SrcType ; + typedef ViewMapping DstType; + typedef ViewMapping SrcType; - template < typename DT , typename ... DP , typename ST , typename ... SP > - KOKKOS_INLINE_FUNCTION - static void assign( Kokkos::DynRankView< DT , DP...> & dst , const Kokkos::View< ST , SP... > & src ) - { - static_assert( is_assignable_value_type - , "View assignment must have same value type or const = non-const" ); + template + KOKKOS_INLINE_FUNCTION static void assign( + Kokkos::DynRankView& dst, const Kokkos::View& src) { + static_assert( + is_assignable_value_type, + "View assignment must have same value type or const = non-const"); - static_assert( is_assignable_layout - , "View assignment must have compatible layout or have rank <= 1" ); + static_assert( + is_assignable_layout, + "View assignment must have compatible layout or have rank <= 1"); // Removed dimension checks... - typedef typename DstType::offset_type dst_offset_type ; - dst.m_map.m_impl_offset = dst_offset_type(std::integral_constant() , src.layout() ); //Check this for integer input1 for padding, etc - dst.m_map.m_impl_handle = Kokkos::Impl::ViewDataHandle< DstTraits >::assign( src.m_map.m_impl_handle , src.m_track ); - dst.m_track.assign( src.m_track , DstTraits::is_managed ); - dst.m_rank = src.Rank ; - } + typedef typename DstType::offset_type dst_offset_type; + dst.m_map.m_impl_offset = dst_offset_type( + std::integral_constant(), + src.layout()); // Check this for integer input1 for padding, etc + dst.m_map.m_impl_handle = Kokkos::Impl::ViewDataHandle::assign( + src.m_map.m_impl_handle, src.m_track); + dst.m_track.assign(src.m_track, DstTraits::is_managed); + dst.m_rank = src.Rank; + } }; -} //end Impl +} // namespace Impl /* \class DynRankView * \brief Container that creates a Kokkos view with rank determined at runtime. @@ -400,7 +384,8 @@ public: * Changes from View * 1. The rank of the DynRankView is returned by the method rank() * 2. Max rank of a DynRankView is 7 - * 3. subview called with 'subview(...)' or 'subdynrankview(...)' (backward compatibility) + * 3. subview called with 'subview(...)' or 'subdynrankview(...)' (backward + * compatibility) * 4. Every subview is returned with LayoutStride * 5. Copy and Copy-Assign View to DynRankView * 6. deep_copy between Views and DynRankViews @@ -408,93 +393,99 @@ public: * */ -template< class > struct is_dyn_rank_view : public std::false_type {}; - -template< class D, class ... P > -struct is_dyn_rank_view< Kokkos::DynRankView > : public std::true_type {}; +template +struct is_dyn_rank_view : public std::false_type {}; +template +struct is_dyn_rank_view > : public std::true_type { +}; -template< typename DataType , class ... Properties > -class DynRankView : public ViewTraits< DataType , Properties ... > -{ - static_assert( !std::is_array::value && !std::is_pointer::value , "Cannot template DynRankView with array or pointer datatype - must be pod" ); - -private: - template < class , class ... > friend class DynRankView ; - template < class , class ... > friend class Kokkos::Impl::ViewMapping ; +template +class DynRankView : public ViewTraits { + static_assert(!std::is_array::value && + !std::is_pointer::value, + "Cannot template DynRankView with array or pointer datatype - " + "must be pod"); -public: - typedef ViewTraits< DataType , Properties ... > drvtraits ; + private: + template + friend class DynRankView; + template + friend class Kokkos::Impl::ViewMapping; - typedef View< DataType******* , Properties...> view_type ; + public: + typedef ViewTraits drvtraits; - typedef ViewTraits< DataType******* , Properties ... > traits ; + typedef View view_type; + typedef ViewTraits traits; -private: - typedef Kokkos::Impl::ViewMapping< traits , typename traits::specialize > map_type ; - typedef Kokkos::Impl::SharedAllocationTracker track_type ; + private: + typedef Kokkos::Impl::ViewMapping + map_type; + typedef Kokkos::Impl::SharedAllocationTracker track_type; - track_type m_track ; - map_type m_map ; + track_type m_track; + map_type m_map; unsigned m_rank; -public: + public: KOKKOS_INLINE_FUNCTION - view_type & DownCast() const { return ( view_type & ) (*this); } + view_type& DownCast() const { return (view_type&)(*this); } KOKKOS_INLINE_FUNCTION - const view_type & ConstDownCast() const { return (const view_type & ) (*this); } + const view_type& ConstDownCast() const { return (const view_type&)(*this); } - //Types below - at least the HostMirror requires the value_type, NOT the rank 7 data_type of the traits + // Types below - at least the HostMirror requires the value_type, NOT the rank + // 7 data_type of the traits /** \brief Compatible view of array of scalar types */ - typedef DynRankView< typename drvtraits::scalar_array_type , - typename drvtraits::array_layout , - typename drvtraits::device_type , - typename drvtraits::memory_traits > - array_type ; + typedef DynRankView< + typename drvtraits::scalar_array_type, typename drvtraits::array_layout, + typename drvtraits::device_type, typename drvtraits::memory_traits> + array_type; /** \brief Compatible view of const data type */ - typedef DynRankView< typename drvtraits::const_data_type , - typename drvtraits::array_layout , - typename drvtraits::device_type , - typename drvtraits::memory_traits > - const_type ; + typedef DynRankView< + typename drvtraits::const_data_type, typename drvtraits::array_layout, + typename drvtraits::device_type, typename drvtraits::memory_traits> + const_type; /** \brief Compatible view of non-const data type */ - typedef DynRankView< typename drvtraits::non_const_data_type , - typename drvtraits::array_layout , - typename drvtraits::device_type , - typename drvtraits::memory_traits > - non_const_type ; + typedef DynRankView< + typename drvtraits::non_const_data_type, typename drvtraits::array_layout, + typename drvtraits::device_type, typename drvtraits::memory_traits> + non_const_type; /** \brief Compatible HostMirror view */ - typedef DynRankView< typename drvtraits::non_const_data_type , - typename drvtraits::array_layout , - typename drvtraits::host_mirror_space > - HostMirror ; - + typedef DynRankView + HostMirror; //---------------------------------------- // Domain rank and extents -// enum { Rank = map_type::Rank }; //Will be dyn rank of 7 always, keep the enum? + // enum { Rank = map_type::Rank }; //Will be dyn rank of 7 always, keep the + // enum? - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - extent( const iType & r ) const - { return m_map.extent(r); } + typename std::enable_if::value, size_t>::type + extent(const iType& r) const { + return m_map.extent(r); + } - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , int >::type - extent_int( const iType & r ) const - { return static_cast(m_map.extent(r)); } + typename std::enable_if::value, int>::type + extent_int(const iType& r) const { + return static_cast(m_map.extent(r)); + } - KOKKOS_INLINE_FUNCTION constexpr - typename traits::array_layout layout() const - { return m_map.layout(); } + KOKKOS_INLINE_FUNCTION constexpr typename traits::array_layout layout() + const { + return m_map.layout(); + } //---------------------------------------- /* Deprecate all 'dimension' functions in favor of @@ -502,421 +493,572 @@ public: */ #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - dimension( const iType & r ) const { return extent( r ); } - - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { return m_map.dimension_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { return m_map.dimension_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { return m_map.dimension_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { return m_map.dimension_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { return m_map.dimension_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { return m_map.dimension_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { return m_map.dimension_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { return m_map.dimension_7(); } + typename std::enable_if::value, size_t>::type + dimension(const iType& r) const { + return extent(r); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { + return m_map.dimension_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { + return m_map.dimension_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { + return m_map.dimension_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { + return m_map.dimension_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { + return m_map.dimension_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { + return m_map.dimension_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { + return m_map.dimension_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { + return m_map.dimension_7(); + } #endif //---------------------------------------- - KOKKOS_INLINE_FUNCTION constexpr size_t size() const { return m_map.extent(0) * - m_map.extent(1) * - m_map.extent(2) * - m_map.extent(3) * - m_map.extent(4) * - m_map.extent(5) * - m_map.extent(6) * - m_map.extent(7); } - - KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { return m_map.stride_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { return m_map.stride_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { return m_map.stride_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { return m_map.stride_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { return m_map.stride_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { return m_map.stride_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { return m_map.stride_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { return m_map.stride_7(); } - - template< typename iType > - KOKKOS_INLINE_FUNCTION void stride( iType * const s ) const { m_map.stride(s); } + KOKKOS_INLINE_FUNCTION constexpr size_t size() const { + return m_map.extent(0) * m_map.extent(1) * m_map.extent(2) * + m_map.extent(3) * m_map.extent(4) * m_map.extent(5) * + m_map.extent(6) * m_map.extent(7); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { + return m_map.stride_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { + return m_map.stride_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { + return m_map.stride_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { + return m_map.stride_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { + return m_map.stride_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { + return m_map.stride_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { + return m_map.stride_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { + return m_map.stride_7(); + } + + template + KOKKOS_INLINE_FUNCTION void stride(iType* const s) const { + m_map.stride(s); + } //---------------------------------------- // Range span is the span which contains all members. - typedef typename map_type::reference_type reference_type ; - typedef typename map_type::pointer_type pointer_type ; + typedef typename map_type::reference_type reference_type; + typedef typename map_type::pointer_type pointer_type; - enum { reference_type_is_lvalue_reference = std::is_lvalue_reference< reference_type >::value }; + enum { + reference_type_is_lvalue_reference = + std::is_lvalue_reference::value + }; KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return m_map.span(); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span()' instead - KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { return m_map.span(); } + KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { + return m_map.span(); + } #endif - KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { return m_map.span_is_contiguous(); } - KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION constexpr bool span_is_contiguous() const { + return m_map.span_is_contiguous(); + } + KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { + return m_map.data(); + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span_is_contigous()' instead - KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { return m_map.span_is_contiguous(); } + KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { + return m_map.span_is_contiguous(); + } // Deprecated, use 'data()' instead - KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { + return m_map.data(); + } #endif //---------------------------------------- // Allow specializations to query their specialized map #ifdef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - implementation_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + implementation_map() const { + return m_map; + } #endif KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - impl_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + impl_map() const { + return m_map; + } //---------------------------------------- -private: - + private: enum { - is_layout_left = std::is_same< typename traits::array_layout - , Kokkos::LayoutLeft >::value , + is_layout_left = + std::is_same::value, - is_layout_right = std::is_same< typename traits::array_layout - , Kokkos::LayoutRight >::value , + is_layout_right = + std::is_same::value, - is_layout_stride = std::is_same< typename traits::array_layout - , Kokkos::LayoutStride >::value , + is_layout_stride = std::is_same::value, - is_default_map = - std::is_same< typename traits::specialize , void >::value && - ( is_layout_left || is_layout_right || is_layout_stride ) + is_default_map = std::is_same::value && + (is_layout_left || is_layout_right || is_layout_stride) }; - template< class Space , bool = Kokkos::Impl::MemorySpaceAccess< Space , typename traits::memory_space >::accessible > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() {} }; + template ::accessible> + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() {} + }; - template< class Space > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() - { Kokkos::abort("Kokkos::DynRankView ERROR: attempt to access inaccessible memory space"); }; + template + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() { + Kokkos::abort( + "Kokkos::DynRankView ERROR: attempt to access inaccessible memory " + "space"); }; + }; // Bounds checking macros -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) // rank of the calling operator - included as first argument in ARG -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - DynRankView::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); \ - Kokkos::Impl::dyn_rank_view_verify_operator_bounds< typename traits::memory_space > ARG ; +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + DynRankView::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); \ + Kokkos::Impl::dyn_rank_view_verify_operator_bounds< \ + typename traits::memory_space> \ + ARG; #else -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - DynRankView::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + DynRankView::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); #endif -public: - + public: KOKKOS_INLINE_FUNCTION constexpr unsigned rank() const { return m_rank; } - - //operators () + // operators () // Rank 0 KOKKOS_INLINE_FUNCTION - reference_type operator()() const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (0 , this->rank(), m_track, m_map) ) - return impl_map().reference(); - //return m_map.reference(0,0,0,0,0,0,0); - } + reference_type operator()() const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((0, this->rank(), m_track, m_map)) + return impl_map().reference(); + // return m_map.reference(0,0,0,0,0,0,0); + } // Rank 1 - // This assumes a contiguous underlying memory (i.e. no padding, no striding...) - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< std::is_same::value && std::is_integral::value, reference_type>::type - operator[](const iType & i0) const - { - //Phalanx is violating this, since they use the operator to access ALL elements in the allocation - //KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map) ) - return data()[i0]; - } + // This assumes a contiguous underlying memory (i.e. no padding, no + // striding...) + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + std::is_same::value && + std::is_integral::value, + reference_type>::type + operator[](const iType& i0) const { + // Phalanx is violating this, since they use the operator to access ALL + // elements in the allocation KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , + // this->rank(), m_track, m_map) ) + return data()[i0]; + } - // This assumes a contiguous underlying memory (i.e. no padding, no striding... - // AND a Trilinos/Sacado scalar type ) - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !std::is_same::value && std::is_integral::value, reference_type>::type - operator[](const iType & i0) const - { -// auto map = impl_map(); - const size_t dim_scalar = m_map.dimension_scalar(); - const size_t bytes = this->span() / dim_scalar; - - typedef Kokkos::View > tmp_view_type; - tmp_view_type rankone_view(this->data(), bytes, dim_scalar); - return rankone_view(i0); - } + // This assumes a contiguous underlying memory (i.e. no padding, no + // striding... AND a Trilinos/Sacado scalar type ) + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !std::is_same::value && + std::is_integral::value, + reference_type>::type + operator[](const iType& i0) const { + // auto map = impl_map(); + const size_t dim_scalar = m_map.dimension_scalar(); + const size_t bytes = this->span() / dim_scalar; + + typedef Kokkos::View< + DataType*, typename traits::array_layout, typename traits::device_type, + Kokkos::MemoryTraits > + tmp_view_type; + tmp_view_type rankone_view(this->data(), bytes, dim_scalar); + return rankone_view(i0); + } // Rank 1 parenthesis - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0); + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0,0,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0, 0, 0, 0, 0, 0, 0); + } // Rank 2 - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1); + } - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1, 0, 0, 0, 0, 0); + } // Rank 3 - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2); + } - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2, 0, 0, 0, 0); + } // Rank 4 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3, 0, 0, 0); + } // Rank 5 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4, 0, 0); + } // Rank 6 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5, 0); + } // Rank 7 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 , typename iType6 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - operator()(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 , const iType6 & i6 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (7 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + operator()(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3, const iType4& i4, const iType5& i5, + const iType6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (7, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } // Rank 0 KOKKOS_INLINE_FUNCTION - reference_type access() const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (0 , this->rank(), m_track, m_map) ) - return impl_map().reference(); - //return m_map.reference(0,0,0,0,0,0,0); - } + reference_type access() const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((0, this->rank(), m_track, m_map)) + return impl_map().reference(); + // return m_map.reference(0,0,0,0,0,0,0); + } // Rank 1 - // Rank 1 parenthesis - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0); - } + // Rank 1 parenthesis + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0); + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (1 , this->rank(), m_track, m_map, i0) ) - return m_map.reference(i0,0,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((1, this->rank(), m_track, m_map, i0)) + return m_map.reference(i0, 0, 0, 0, 0, 0, 0); + } // Rank 2 - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1); + } - template< typename iType0 , typename iType1 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (2 , this->rank(), m_track, m_map, i0, i1) ) - return m_map.reference(i0,i1,0,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((2, this->rank(), m_track, m_map, i0, i1)) + return m_map.reference(i0, i1, 0, 0, 0, 0, 0); + } // Rank 3 - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2); + } - template< typename iType0 , typename iType1 , typename iType2 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (3 , this->rank(), m_track, m_map, i0, i1, i2) ) - return m_map.reference(i0,i1,i2,0,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (3, this->rank(), m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2, 0, 0, 0, 0); + } // Rank 4 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (4 , this->rank(), m_track, m_map, i0, i1, i2, i3) ) - return m_map.reference(i0,i1,i2,i3,0,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, + const iType3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (4, this->rank(), m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3, 0, 0, 0); + } // Rank 5 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (5 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4) ) - return m_map.reference(i0,i1,i2,i3,i4,0,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (5, this->rank(), m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4, 0, 0); + } // Rank 6 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_same::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_same::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< !(std::is_same::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (6 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,0); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + !(std::is_same::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4, const iType5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (6, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5, 0); + } // Rank 7 - template< typename iType0 , typename iType1 , typename iType2 , typename iType3, typename iType4 , typename iType5 , typename iType6 > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< (std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value && std::is_integral::value), reference_type>::type - access(const iType0 & i0 , const iType1 & i1 , const iType2 & i2 , const iType3 & i3 , const iType4 & i4 , const iType5 & i5 , const iType6 & i6 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (7 , this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + (std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value && std::is_integral::value && + std::is_integral::value), + reference_type>::type + access(const iType0& i0, const iType1& i1, const iType2& i2, const iType3& i3, + const iType4& i4, const iType5& i5, const iType6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (7, this->rank(), m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } #undef KOKKOS_IMPL_VIEW_OPERATOR_VERIFY @@ -927,405 +1069,393 @@ public: ~DynRankView() {} KOKKOS_INLINE_FUNCTION - DynRankView() : m_track(), m_map(), m_rank() {} //Default ctor + DynRankView() : m_track(), m_map(), m_rank() {} // Default ctor KOKKOS_INLINE_FUNCTION - DynRankView( const DynRankView & rhs ) : m_track( rhs.m_track ), m_map( rhs.m_map ), m_rank(rhs.m_rank) {} + DynRankView(const DynRankView& rhs) + : m_track(rhs.m_track), m_map(rhs.m_map), m_rank(rhs.m_rank) {} KOKKOS_INLINE_FUNCTION - DynRankView( DynRankView && rhs ) : m_track( rhs.m_track ), m_map( rhs.m_map ), m_rank(rhs.m_rank) {} + DynRankView(DynRankView&& rhs) + : m_track(rhs.m_track), m_map(rhs.m_map), m_rank(rhs.m_rank) {} KOKKOS_INLINE_FUNCTION - DynRankView & operator = ( const DynRankView & rhs ) { m_track = rhs.m_track; m_map = rhs.m_map; m_rank = rhs.m_rank; return *this; } + DynRankView& operator=(const DynRankView& rhs) { + m_track = rhs.m_track; + m_map = rhs.m_map; + m_rank = rhs.m_rank; + return *this; + } KOKKOS_INLINE_FUNCTION - DynRankView & operator = ( DynRankView && rhs ) { m_track = rhs.m_track; m_map = rhs.m_map; m_rank = rhs.m_rank; return *this; } + DynRankView& operator=(DynRankView&& rhs) { + m_track = rhs.m_track; + m_map = rhs.m_map; + m_rank = rhs.m_rank; + return *this; + } //---------------------------------------- // Compatible view copy constructor and assignment // may assign unmanaged from managed. - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView( const DynRankView & rhs ) - : m_track( rhs.m_track , traits::is_managed ) - , m_map() - , m_rank(rhs.m_rank) - { - typedef typename DynRankView ::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible DynRankView copy construction" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - } + template + KOKKOS_INLINE_FUNCTION DynRankView(const DynRankView& rhs) + : m_track(rhs.m_track, traits::is_managed), m_map(), m_rank(rhs.m_rank) { + typedef typename DynRankView::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible DynRankView copy construction"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + } - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView & operator = (const DynRankView & rhs ) - { - typedef typename DynRankView ::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible DynRankView copy construction" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - m_track.assign( rhs.m_track , traits::is_managed ); - m_rank = rhs.rank(); - return *this; - } + template + KOKKOS_INLINE_FUNCTION DynRankView& operator=( + const DynRankView& rhs) { + typedef typename DynRankView::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible DynRankView copy construction"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + m_track.assign(rhs.m_track, traits::is_managed); + m_rank = rhs.rank(); + return *this; + } -// Copy/Assign View to DynRankView - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView( const View & rhs ) - : m_track() - , m_map() - , m_rank( rhs.Rank ) - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , Kokkos::Impl::ViewToDynRankViewTag > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View to DynRankView copy construction" ); - Mapping::assign( *this , rhs ); - } + // Copy/Assign View to DynRankView + template + KOKKOS_INLINE_FUNCTION DynRankView(const View& rhs) + : m_track(), m_map(), m_rank(rhs.Rank) { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible View to DynRankView copy construction"); + Mapping::assign(*this, rhs); + } - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - DynRankView & operator = ( const View & rhs ) - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , Kokkos::Impl::ViewToDynRankViewTag > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View to DynRankView copy assignment" ); - Mapping::assign( *this , rhs ); - return *this ; - } + template + KOKKOS_INLINE_FUNCTION DynRankView& operator=(const View& rhs) { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible View to DynRankView copy assignment"); + Mapping::assign(*this, rhs); + return *this; + } //---------------------------------------- // Allocation tracking properties KOKKOS_INLINE_FUNCTION - int use_count() const - { return m_track.use_count(); } + int use_count() const { return m_track.use_count(); } - inline - const std::string label() const - { return m_track.template get_label< typename traits::memory_space >(); } + inline const std::string label() const { + return m_track.template get_label(); + } //---------------------------------------- // Allocation according to allocation properties and array layout - // unused arg_layout dimensions must be set to KOKKOS_INVALID_INDEX so that rank deduction can properly take place - template< class ... P > - explicit inline - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() - , m_map() - , m_rank( Impl::DynRankDimTraits::template computeRank< typename traits::array_layout, P...>(arg_prop, arg_layout) ) - { - // Append layout and spaces if not input - typedef Kokkos::Impl::ViewCtorProp< P ... > alloc_prop_input ; - - // use 'std::integral_constant' for non-types - // to avoid duplicate class error. - typedef Kokkos::Impl::ViewCtorProp - < P ... - , typename std::conditional - < alloc_prop_input::has_label - , std::integral_constant - , typename std::string - >::type - , typename std::conditional - < alloc_prop_input::has_memory_space - , std::integral_constant - , typename traits::device_type::memory_space - >::type - , typename std::conditional - < alloc_prop_input::has_execution_space - , std::integral_constant - , typename traits::device_type::execution_space - >::type - > alloc_prop ; - - static_assert( traits::is_managed - , "View allocation constructor requires managed memory" ); - - if ( alloc_prop::initialize && + // unused arg_layout dimensions must be set to KOKKOS_INVALID_INDEX so that + // rank deduction can properly take place + template + explicit inline DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track(), + m_map(), + m_rank(Impl::DynRankDimTraits:: + template computeRank( + arg_prop, arg_layout)) { + // Append layout and spaces if not input + typedef Kokkos::Impl::ViewCtorProp alloc_prop_input; + + // use 'std::integral_constant' for non-types + // to avoid duplicate class error. + typedef Kokkos::Impl::ViewCtorProp< + P..., + typename std::conditional, + typename std::string>::type, + typename std::conditional< + alloc_prop_input::has_memory_space, + std::integral_constant, + typename traits::device_type::memory_space>::type, + typename std::conditional< + alloc_prop_input::has_execution_space, + std::integral_constant, + typename traits::device_type::execution_space>::type> + alloc_prop; + + static_assert(traits::is_managed, + "View allocation constructor requires managed memory"); + + if (alloc_prop::initialize && #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - ! alloc_prop::execution_space::is_initialized() + !alloc_prop::execution_space::is_initialized() #else - ! alloc_prop::execution_space::impl_is_initialized() + !alloc_prop::execution_space::impl_is_initialized() #endif - ) { - // If initializing view data then - // the execution space must be initialized. - Kokkos::Impl::throw_runtime_exception("Constructing DynRankView and initializing data with uninitialized execution space"); - } + ) { + // If initializing view data then + // the execution space must be initialized. + Kokkos::Impl::throw_runtime_exception( + "Constructing DynRankView and initializing data with uninitialized " + "execution space"); + } - // Copy the input allocation properties with possibly defaulted properties - alloc_prop prop_copy( arg_prop ); + // Copy the input allocation properties with possibly defaulted properties + alloc_prop prop_copy(arg_prop); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - // If allocating in CudaUVMSpace must fence before and after - // the allocation to protect against possible concurrent access - // on the CPU and the GPU. - // Fence using the trait's executon space (which will be Kokkos::Cuda) - // to avoid incomplete type errors from usng Kokkos::Cuda directly. - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } +#if defined(KOKKOS_ENABLE_CUDA) + // If allocating in CudaUVMSpace must fence before and after + // the allocation to protect against possible concurrent access + // on the CPU and the GPU. + // Fence using the trait's executon space (which will be Kokkos::Cuda) + // to avoid incomplete type errors from usng Kokkos::Cuda directly. + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); + } #endif -//------------------------------------------------------------ + //------------------------------------------------------------ - Kokkos::Impl::SharedAllocationRecord<> * - record = m_map.allocate_shared( prop_copy, Impl::DynRankDimTraits::template createLayout(arg_prop, arg_layout) ); + Kokkos::Impl::SharedAllocationRecord<>* record = m_map.allocate_shared( + prop_copy, + Impl::DynRankDimTraits:: + template createLayout(arg_prop, arg_layout)); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } -#endif -//------------------------------------------------------------ - - // Setup and initialization complete, start tracking - m_track.assign_allocated_record_to_uninitialized( record ); +#if defined(KOKKOS_ENABLE_CUDA) + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); } +#endif + //------------------------------------------------------------ + // Setup and initialization complete, start tracking + m_track.assign_allocated_record_to_uninitialized(record); + } // Wrappers - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() // No memory tracking - , m_map( arg_prop , Impl::DynRankDimTraits::template createLayout(arg_prop, arg_layout) ) - , m_rank( Impl::DynRankDimTraits::template computeRank< typename traits::array_layout, P...>(arg_prop, arg_layout) ) - { - static_assert( - std::is_same< pointer_type - , typename Impl::ViewCtorProp< P... >::pointer_type - >::value , - "Constructing DynRankView to wrap user memory must supply matching pointer type" ); - } + template + explicit KOKKOS_INLINE_FUNCTION DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track() // No memory tracking + , + m_map(arg_prop, + Impl::DynRankDimTraits:: + template createLayout(arg_prop, arg_layout)), + m_rank(Impl::DynRankDimTraits:: + template computeRank( + arg_prop, arg_layout)) { + static_assert( + std::is_same::pointer_type>::value, + "Constructing DynRankView to wrap user memory must supply matching " + "pointer type"); + } //---------------------------------------- - //Constructor(s) + // Constructor(s) // Simple dimension-only layout - template< class ... P > - explicit inline - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 =KOKKOS_INVALID_INDEX - , const size_t arg_N1 =KOKKOS_INVALID_INDEX - , const size_t arg_N2 =KOKKOS_INVALID_INDEX - , const size_t arg_N3 =KOKKOS_INVALID_INDEX - , const size_t arg_N4 =KOKKOS_INVALID_INDEX - , const size_t arg_N5 =KOKKOS_INVALID_INDEX - , const size_t arg_N6 =KOKKOS_INVALID_INDEX - , const size_t arg_N7 =KOKKOS_INVALID_INDEX - ) - : DynRankView( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - {} - - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - DynRankView( const Kokkos::Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Kokkos::Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 =KOKKOS_INVALID_INDEX - , const size_t arg_N1 =KOKKOS_INVALID_INDEX - , const size_t arg_N2 =KOKKOS_INVALID_INDEX - , const size_t arg_N3 =KOKKOS_INVALID_INDEX - , const size_t arg_N4 =KOKKOS_INVALID_INDEX - , const size_t arg_N5 =KOKKOS_INVALID_INDEX - , const size_t arg_N6 =KOKKOS_INVALID_INDEX - , const size_t arg_N7 =KOKKOS_INVALID_INDEX - ) - : DynRankView( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - {} + template + explicit inline DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = KOKKOS_INVALID_INDEX, + const size_t arg_N1 = KOKKOS_INVALID_INDEX, + const size_t arg_N2 = KOKKOS_INVALID_INDEX, + const size_t arg_N3 = KOKKOS_INVALID_INDEX, + const size_t arg_N4 = KOKKOS_INVALID_INDEX, + const size_t arg_N5 = KOKKOS_INVALID_INDEX, + const size_t arg_N6 = KOKKOS_INVALID_INDEX, + const size_t arg_N7 = KOKKOS_INVALID_INDEX) + : DynRankView(arg_prop, typename traits::array_layout( + arg_N0, arg_N1, arg_N2, arg_N3, arg_N4, + arg_N5, arg_N6, arg_N7)) {} + + template + explicit KOKKOS_INLINE_FUNCTION DynRankView( + const Kokkos::Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = KOKKOS_INVALID_INDEX, + const size_t arg_N1 = KOKKOS_INVALID_INDEX, + const size_t arg_N2 = KOKKOS_INVALID_INDEX, + const size_t arg_N3 = KOKKOS_INVALID_INDEX, + const size_t arg_N4 = KOKKOS_INVALID_INDEX, + const size_t arg_N5 = KOKKOS_INVALID_INDEX, + const size_t arg_N6 = KOKKOS_INVALID_INDEX, + const size_t arg_N7 = KOKKOS_INVALID_INDEX) + : DynRankView(arg_prop, typename traits::array_layout( + arg_N0, arg_N1, arg_N2, arg_N3, arg_N4, + arg_N5, arg_N6, arg_N7)) {} // Allocate with label and layout - template< typename Label > - explicit inline - DynRankView( const Label & arg_label - , typename std::enable_if< - Kokkos::Impl::is_view_label

    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 diff --git a/doc/src/Eqs/fix_nh1.tex b/doc/src/Eqs/fix_nh1.tex deleted file mode 100644 index 3e780f2772..0000000000 --- a/doc/src/Eqs/fix_nh1.tex +++ /dev/null @@ -1,36 +0,0 @@ -\documentclass[24pt]{article} - -\pagestyle{empty} -\Huge - -\begin{document} - -\mathchardef\mhyphen="2D - -% The imaginary unit -\providecommand*{\iu}% - {\ensuremath{{\rm i}}} - - -\begin{eqnarray*} -\exp \left(\iu{} L \Delta t \right) &=&Ê -\exp \left(\iu{} L_{\rm T\mhyphen baro} \frac{\Delta t}{2} \right) -\exp \left(\iu{} L_{\rm T\mhyphen part} \frac{\Delta t}{2} \right) -\exp \left(\iu{} L_{\epsilon , 2} \frac{\Delta t}{2} \right) -\exp \left(\iu{} L_{2}^{(2)} \frac{\Delta t}{2} \right) \\ -&&\times \left[ -\exp \left(\iu{} L_{2}^{(1)} \frac{\Delta t}{2n} \right) -\exp \left(\iu{} L_{\epsilon , 1} \frac{\Delta t}{2n} \right) -\exp \left(\iu{} L_1 \frac{\Delta t}{n} \right) -\exp \left(\iu{} L_{\epsilon , 1} \frac{\Delta t}{2n} \right) -\exp \left(\iu{} L_{2}^{(1)} \frac{\Delta t}{2n} \right) -\right]^n \\ -&&\times -\exp \left(\iu{} L_{2}^{(2)} \frac{\Delta t}{2} \right) -\exp \left(\iu{} L_{\epsilon , 2} \frac{\Delta t}{2} \right) -\exp \left(\iu{} L_{\rm T\mhyphen part} \frac{\Delta t}{2} \right) -\exp \left(\iu{} L_{\rm T\mhyphen baro} \frac{\Delta t}{2} \right) \\ -&&+ \mathcal{O} \left(\Delta t^3 \right) -\end{eqnarray*} - -\end{document} diff --git a/doc/src/Eqs/fix_nphug.jpg b/doc/src/Eqs/fix_nphug.jpg deleted file mode 100644 index a3a67e7b7bebc1e987f0cc415288967337770f2e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7506 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 Ye6ywOH(lKKyeKUYWloKXocjMa0X%q#5dZ)H diff --git a/doc/src/Eqs/fix_nphug.tex b/doc/src/Eqs/fix_nphug.tex deleted file mode 100644 index 4e162b69b7..0000000000 --- a/doc/src/Eqs/fix_nphug.tex +++ /dev/null @@ -1,9 +0,0 @@ -\documentstyle[12pt]{article} - -\begin{document} - -$$ -T_t - T = \frac{\left(\frac{1}{2}\left(P + P_0\right)\left(V_0 - V\right) + E_0 - E\right)}{N_{dof} k_B } = Delta -$$ - -\end{document} diff --git a/doc/src/Eqs/fix_orient_fcc.jpg b/doc/src/Eqs/fix_orient_fcc.jpg deleted file mode 100644 index b22e6c9c2056cdc4e7a28d1fb327e867741eec85..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 26005 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

-class UnorderedMapInsertResult -{ -private: - enum Status{ - SUCCESS = 1u << 31 - , EXISTING = 1u << 30 - , FREED_EXISTING = 1u << 29 - , LIST_LENGTH_MASK = ~(SUCCESS | EXISTING | FREED_EXISTING) +class UnorderedMapInsertResult { + private: + enum Status { + SUCCESS = 1u << 31, + EXISTING = 1u << 30, + FREED_EXISTING = 1u << 29, + LIST_LENGTH_MASK = ~(SUCCESS | EXISTING | FREED_EXISTING) }; -public: + public: /// Did the map successful insert the key/value pair KOKKOS_FORCEINLINE_FUNCTION bool success() const { return (m_status & SUCCESS); } @@ -102,7 +100,7 @@ public: KOKKOS_FORCEINLINE_FUNCTION bool existing() const { return (m_status & EXISTING); } - /// Did the map fail to insert the key due to insufficient capacity + /// Did the map fail to insert the key due to insufficent capacity KOKKOS_FORCEINLINE_FUNCTION bool failed() const { return m_index == UnorderedMapInvalidIndex; } @@ -121,32 +119,27 @@ public: uint32_t index() const { return m_index; } KOKKOS_FORCEINLINE_FUNCTION - UnorderedMapInsertResult() - : m_index(UnorderedMapInvalidIndex) - , m_status(0) - {} + UnorderedMapInsertResult() : m_index(UnorderedMapInvalidIndex), m_status(0) {} KOKKOS_FORCEINLINE_FUNCTION - void increment_list_position() - { + void increment_list_position() { m_status += (list_position() < LIST_LENGTH_MASK) ? 1u : 0u; } KOKKOS_FORCEINLINE_FUNCTION - void set_existing(uint32_t i, bool arg_freed_existing) - { + void set_existing(uint32_t i, bool arg_freed_existing) { m_index = i; - m_status = EXISTING | (arg_freed_existing ? FREED_EXISTING : 0u) | list_position(); + m_status = + EXISTING | (arg_freed_existing ? FREED_EXISTING : 0u) | list_position(); } KOKKOS_FORCEINLINE_FUNCTION - void set_success(uint32_t i) - { - m_index = i; + void set_success(uint32_t i) { + m_index = i; m_status = SUCCESS | list_position(); } -private: + private: uint32_t m_index; uint32_t m_status; }; @@ -206,26 +199,26 @@ private: /// \tparam EqualTo Definition of the equality function for instances of /// Key. The default will do a bitwise equality comparison. /// -template < typename Key - , typename Value - , typename Device = Kokkos::DefaultExecutionSpace - , typename Hasher = pod_hash::type> - , typename EqualTo = pod_equal_to::type> - > -class UnorderedMap -{ -private: - typedef typename ViewTraits::host_mirror_space host_mirror_space ; -public: +template ::type>, + typename EqualTo = + pod_equal_to::type> > +class UnorderedMap { + private: + typedef typename ViewTraits::host_mirror_space + host_mirror_space; + + public: //! \name Public types and constants //@{ - //key_types + // key_types typedef Key declared_key_type; typedef typename Impl::remove_const::type key_type; typedef typename Impl::add_const::type const_key_type; - //value_types + // value_types typedef Value declared_value_type; typedef typename Impl::remove_const::type value_type; typedef typename Impl::add_const::type const_value_type; @@ -233,116 +226,126 @@ public: typedef Device device_type; typedef typename Device::execution_space execution_space; typedef Hasher hasher_type; - typedef EqualTo equal_to_type; + typedef EqualTo equal_to_type; typedef uint32_t size_type; - //map_types - typedef UnorderedMap declared_map_type; - typedef UnorderedMap insertable_map_type; - typedef UnorderedMap modifiable_map_type; - typedef UnorderedMap const_map_type; - - static const bool is_set = std::is_same::value; - static const bool has_const_key = std::is_same::value; - static const bool has_const_value = is_set || std::is_same::value; - - static const bool is_insertable_map = !has_const_key && (is_set || !has_const_value); + // map_types + typedef UnorderedMap + declared_map_type; + typedef UnorderedMap + insertable_map_type; + typedef UnorderedMap + modifiable_map_type; + typedef UnorderedMap + const_map_type; + + static const bool is_set = std::is_same::value; + static const bool has_const_key = + std::is_same::value; + static const bool has_const_value = + is_set || std::is_same::value; + + static const bool is_insertable_map = + !has_const_key && (is_set || !has_const_value); static const bool is_modifiable_map = has_const_key && !has_const_value; - static const bool is_const_map = has_const_key && has_const_value; - + static const bool is_const_map = has_const_key && has_const_value; typedef UnorderedMapInsertResult insert_result; - typedef UnorderedMap HostMirror; + typedef UnorderedMap + HostMirror; typedef Impl::UnorderedMapHistogram histogram_type; //@} -private: + private: enum { invalid_index = ~static_cast(0) }; - typedef typename Impl::if_c< is_set, int, declared_value_type>::type impl_value_type; + typedef typename Impl::if_c::type + impl_value_type; - typedef typename Impl::if_c< is_insertable_map - , View< key_type *, device_type> - , View< const key_type *, device_type, MemoryTraits > - >::type key_type_view; + typedef typename Impl::if_c< + is_insertable_map, View, + View > >::type + key_type_view; - typedef typename Impl::if_c< is_insertable_map || is_modifiable_map - , View< impl_value_type *, device_type> - , View< const impl_value_type *, device_type, MemoryTraits > - >::type value_type_view; + typedef typename Impl::if_c, + View > >::type + value_type_view; - typedef typename Impl::if_c< is_insertable_map - , View< size_type *, device_type> - , View< const size_type *, device_type, MemoryTraits > - >::type size_type_view; + typedef typename Impl::if_c< + is_insertable_map, View, + View > >::type + size_type_view; - typedef typename Impl::if_c< is_insertable_map - , Bitset< execution_space > - , ConstBitset< execution_space> - >::type bitset_type; + typedef typename Impl::if_c, + ConstBitset >::type bitset_type; enum { modified_idx = 0, erasable_idx = 1, failed_insert_idx = 2 }; enum { num_scalars = 3 }; - typedef View< int[num_scalars], LayoutLeft, device_type> scalars_view; + typedef View scalars_view; -public: + public: //! \name Public member functions //@{ UnorderedMap() - : m_bounded_insert() - , m_hasher() - , m_equal_to() - , m_size() - , m_available_indexes() - , m_hash_lists() - , m_next_index() - , m_keys() - , m_values() - , m_scalars() - {} + : m_bounded_insert(), + m_hasher(), + m_equal_to(), + m_size(), + m_available_indexes(), + m_hash_lists(), + m_next_index(), + m_keys(), + m_values(), + m_scalars() {} /// \brief Constructor /// - /// \param capacity_hint [in] Initial guess of how many unique keys will be inserted into the map - /// \param hash [in] Hasher function for \c Key instances. The + /// \param capacity_hint [in] Initial guess of how many unique keys will be + /// inserted into the map \param hash [in] Hasher function for \c Key + /// instances. The /// default value usually suffices. - UnorderedMap( size_type capacity_hint, hasher_type hasher = hasher_type(), equal_to_type equal_to = equal_to_type() ) - : m_bounded_insert(true) - , m_hasher(hasher) - , m_equal_to(equal_to) - , m_size() - , m_available_indexes(calculate_capacity(capacity_hint)) - , m_hash_lists(ViewAllocateWithoutInitializing("UnorderedMap hash list"), Impl::find_hash_size(capacity())) - , m_next_index(ViewAllocateWithoutInitializing("UnorderedMap next index"), capacity()+1) // +1 so that the *_at functions can always return a valid reference - , m_keys("UnorderedMap keys",capacity()+1) - , m_values("UnorderedMap values",(is_set? 1 : capacity()+1)) - , m_scalars("UnorderedMap scalars") - { + UnorderedMap(size_type capacity_hint, hasher_type hasher = hasher_type(), + equal_to_type equal_to = equal_to_type()) + : m_bounded_insert(true), + m_hasher(hasher), + m_equal_to(equal_to), + m_size(), + m_available_indexes(calculate_capacity(capacity_hint)), + m_hash_lists(ViewAllocateWithoutInitializing("UnorderedMap hash list"), + Impl::find_hash_size(capacity())), + m_next_index(ViewAllocateWithoutInitializing("UnorderedMap next index"), + capacity() + 1) // +1 so that the *_at functions can + // always return a valid reference + , + m_keys("UnorderedMap keys", capacity() + 1), + m_values("UnorderedMap values", (is_set ? 1 : capacity() + 1)), + m_scalars("UnorderedMap scalars") { if (!is_insertable_map) { - throw std::runtime_error("Cannot construct a non-insertable (i.e. const key_type) unordered_map"); + throw std::runtime_error( + "Cannot construct a non-insertable (i.e. const key_type) " + "unordered_map"); } Kokkos::deep_copy(m_hash_lists, invalid_index); Kokkos::deep_copy(m_next_index, invalid_index); } - void reset_failed_insert_flag() - { - reset_flag(failed_insert_idx); - } + void reset_failed_insert_flag() { reset_flag(failed_insert_idx); } - histogram_type get_histogram() - { - return histogram_type(*this); - } + histogram_type get_histogram() { return histogram_type(*this); } //! Clear all entries in the table. - void clear() - { + void clear() { m_bounded_insert = true; if (capacity() == 0) return; @@ -353,15 +356,13 @@ public: Kokkos::deep_copy(m_next_index, invalid_index); { const key_type tmp = key_type(); - Kokkos::deep_copy(m_keys,tmp); + Kokkos::deep_copy(m_keys, tmp); } - if (is_set){ + if (is_set) { const impl_value_type tmp = impl_value_type(); - Kokkos::deep_copy(m_values,tmp); - } - { - Kokkos::deep_copy(m_scalars, 0); + Kokkos::deep_copy(m_values, tmp); } + { Kokkos::deep_copy(m_scalars, 0); } } /// \brief Change the capacity of the the map @@ -374,24 +375,23 @@ public: /// /// This is not a device function; it may not be /// called in a parallel kernel. - bool rehash(size_type requested_capacity = 0) - { + bool rehash(size_type requested_capacity = 0) { const bool bounded_insert = (capacity() == 0) || (size() == 0u); - return rehash(requested_capacity, bounded_insert ); + return rehash(requested_capacity, bounded_insert); } - bool rehash(size_type requested_capacity, bool bounded_insert) - { - if(!is_insertable_map) return false; + bool rehash(size_type requested_capacity, bool bounded_insert) { + if (!is_insertable_map) return false; const size_type curr_size = size(); - requested_capacity = (requested_capacity < curr_size) ? curr_size : requested_capacity; + requested_capacity = + (requested_capacity < curr_size) ? curr_size : requested_capacity; insertable_map_type tmp(requested_capacity, m_hasher, m_equal_to); if (curr_size) { tmp.m_bounded_insert = false; - Impl::UnorderedMapRehash f(tmp,*this); + Impl::UnorderedMapRehash f(tmp, *this); f.apply(); } tmp.m_bounded_insert = bounded_insert; @@ -408,9 +408,8 @@ public: /// Note that this is not a device function; it cannot be called in /// a parallel kernel. The value is not stored as a variable; it /// must be computed. - size_type size() const - { - if( capacity() == 0u ) return 0u; + size_type size() const { + if (capacity() == 0u) return 0u; if (modified()) { m_size = m_available_indexes.count(); reset_flag(modified_idx); @@ -423,18 +422,13 @@ public: /// This is not a device function; it may not be /// called in a parallel kernel. The value is not stored as a /// variable; it must be computed. - bool failed_insert() const - { - return get_flag(failed_insert_idx); - } + bool failed_insert() const { return get_flag(failed_insert_idx); } - bool erasable() const - { + bool erasable() const { return is_insertable_map ? get_flag(erasable_idx) : false; } - bool begin_erase() - { + bool begin_erase() { bool result = !erasable(); if (is_insertable_map && result) { execution_space().fence(); @@ -444,8 +438,7 @@ public: return result; } - bool end_erase() - { + bool end_erase() { bool result = erasable(); if (is_insertable_map && result) { execution_space().fence(); @@ -462,8 +455,7 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_FORCEINLINE_FUNCTION - size_type capacity() const - { return m_available_indexes.size(); } + size_type capacity() const { return m_available_indexes.size(); } /// \brief The number of hash table "buckets." /// @@ -476,13 +468,11 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_INLINE_FUNCTION - size_type hash_capacity() const - { return m_hash_lists.extent(0); } + size_type hash_capacity() const { return m_hash_lists.extent(0); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- - /// This is a device function; it may be called in a parallel /// kernel. As discussed in the class documentation, it need not /// succeed. The return value tells you if it did. @@ -492,136 +482,138 @@ public: /// using this class as a set (with Value = void), then you need not /// provide this value. KOKKOS_INLINE_FUNCTION - insert_result insert(key_type const& k, impl_value_type const&v = impl_value_type()) const - { + insert_result insert(key_type const &k, + impl_value_type const &v = impl_value_type()) const { insert_result result; - if ( !is_insertable_map || capacity() == 0u || m_scalars((int)erasable_idx) ) { + if (!is_insertable_map || capacity() == 0u || + m_scalars((int)erasable_idx)) { return result; } - if ( !m_scalars((int)modified_idx) ) { + if (!m_scalars((int)modified_idx)) { m_scalars((int)modified_idx) = true; } - int volatile & failed_insert_ref = m_scalars((int)failed_insert_idx) ; + int volatile &failed_insert_ref = m_scalars((int)failed_insert_idx); const size_type hash_value = m_hasher(k); - const size_type hash_list = hash_value % m_hash_lists.extent(0); + const size_type hash_list = hash_value % m_hash_lists.extent(0); - size_type * curr_ptr = & m_hash_lists[ hash_list ]; - size_type new_index = invalid_index ; + size_type *curr_ptr = &m_hash_lists[hash_list]; + size_type new_index = invalid_index; // Force integer multiply to long - size_type index_hint = static_cast( (static_cast(hash_list) * capacity()) / m_hash_lists.extent(0)); + size_type index_hint = static_cast( + (static_cast(hash_list) * capacity()) / m_hash_lists.extent(0)); size_type find_attempts = 0; enum : unsigned { bounded_find_attempts = 32u }; - const size_type max_attempts = (m_bounded_insert && (bounded_find_attempts < m_available_indexes.max_hint()) ) ? - bounded_find_attempts : - m_available_indexes.max_hint(); + const size_type max_attempts = + (m_bounded_insert && + (bounded_find_attempts < m_available_indexes.max_hint())) + ? bounded_find_attempts + : m_available_indexes.max_hint(); - bool not_done = true ; + bool not_done = true; -#if defined( __MIC__ ) - #pragma noprefetch +#if defined(__MIC__) +#pragma noprefetch #endif - while ( not_done ) { - + while (not_done) { // Continue searching the unordered list for this key, // list will only be appended during insert phase. // Need volatile_load as other threads may be appending. size_type curr = volatile_load(curr_ptr); - KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); -#if defined( __MIC__ ) - #pragma noprefetch + KOKKOS_NONTEMPORAL_PREFETCH_LOAD( + &m_keys[curr != invalid_index ? curr : 0]); +#if defined(__MIC__) +#pragma noprefetch #endif - while ( curr != invalid_index && ! m_equal_to( volatile_load(&m_keys[curr]), k) ) { + while (curr != invalid_index && + !m_equal_to(volatile_load(&m_keys[curr]), k)) { result.increment_list_position(); index_hint = curr; - curr_ptr = &m_next_index[curr]; - curr = volatile_load(curr_ptr); - KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); + curr_ptr = &m_next_index[curr]; + curr = volatile_load(curr_ptr); + KOKKOS_NONTEMPORAL_PREFETCH_LOAD( + &m_keys[curr != invalid_index ? curr : 0]); } //------------------------------------------------------------ // If key already present then return that index. - if ( curr != invalid_index ) { - + if (curr != invalid_index) { const bool free_existing = new_index != invalid_index; - if ( free_existing ) { + if (free_existing) { // Previously claimed an unused entry that was not inserted. // Release this unused entry immediately. - if (!m_available_indexes.reset(new_index) ) { + if (!m_available_indexes.reset(new_index)) { printf("Unable to free existing\n"); } - } result.set_existing(curr, free_existing); - not_done = false ; + not_done = false; } //------------------------------------------------------------ // Key is not currently in the map. // If the thread has claimed an entry try to insert now. else { - //------------------------------------------------------------ // If have not already claimed an unused entry then do so now. if (new_index == invalid_index) { - bool found = false; // use the hash_list as the flag for the search direction - Kokkos::tie(found, index_hint) = m_available_indexes.find_any_unset_near( index_hint, hash_list ); + Kokkos::tie(found, index_hint) = + m_available_indexes.find_any_unset_near(index_hint, hash_list); // found and index and this thread set it - if ( !found && ++find_attempts >= max_attempts ) { + if (!found && ++find_attempts >= max_attempts) { failed_insert_ref = true; - not_done = false ; - } - else if (m_available_indexes.set(index_hint) ) { + not_done = false; + } else if (m_available_indexes.set(index_hint)) { new_index = index_hint; // Set key and value KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_keys[new_index]); - m_keys[new_index] = k ; + m_keys[new_index] = k; if (!is_set) { KOKKOS_NONTEMPORAL_PREFETCH_STORE(&m_values[new_index]); - m_values[new_index] = v ; + m_values[new_index] = v; } // Do not proceed until key and value are updated in global memory memory_fence(); } - } - else if (failed_insert_ref) { + } else if (failed_insert_ref) { not_done = false; } // Attempt to append claimed entry into the list. - // Another thread may also be trying to append the same list so protect with atomic. - if ( new_index != invalid_index && - curr == atomic_compare_exchange(curr_ptr, static_cast(invalid_index), new_index) ) { + // Another thread may also be trying to append the same list so protect + // with atomic. + if (new_index != invalid_index && + curr == atomic_compare_exchange( + curr_ptr, static_cast(invalid_index), + new_index)) { // Succeeded in appending result.set_success(new_index); - not_done = false ; + not_done = false; } } - } // while ( not_done ) + } // while ( not_done ) - return result ; + return result; } KOKKOS_INLINE_FUNCTION - bool erase(key_type const& k) const - { + bool erase(key_type const &k) const { bool result = false; - if(is_insertable_map && 0u < capacity() && m_scalars((int)erasable_idx)) { - - if ( ! m_scalars((int)modified_idx) ) { + if (is_insertable_map && 0u < capacity() && m_scalars((int)erasable_idx)) { + if (!m_scalars((int)modified_idx)) { m_scalars((int)modified_idx) = true; } @@ -643,13 +635,15 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_INLINE_FUNCTION - size_type find( const key_type & k) const - { - size_type curr = 0u < capacity() ? m_hash_lists( m_hasher(k) % m_hash_lists.extent(0) ) : invalid_index ; + size_type find(const key_type &k) const { + size_type curr = 0u < capacity() + ? m_hash_lists(m_hasher(k) % m_hash_lists.extent(0)) + : invalid_index; KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); - while (curr != invalid_index && !m_equal_to( m_keys[curr], k) ) { - KOKKOS_NONTEMPORAL_PREFETCH_LOAD(&m_keys[curr != invalid_index ? curr : 0]); + while (curr != invalid_index && !m_equal_to(m_keys[curr], k)) { + KOKKOS_NONTEMPORAL_PREFETCH_LOAD( + &m_keys[curr != invalid_index ? curr : 0]); curr = m_next_index[curr]; } @@ -661,11 +655,7 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_INLINE_FUNCTION - bool exists( const key_type & k) const - { - return valid_at(find(k)); - } - + bool exists(const key_type &k) const { return valid_at(find(k)); } /// \brief Get the value with \c i as its direct index. /// @@ -676,10 +666,10 @@ public: /// /// 'const value_type' via Cuda texture fetch must return by value. KOKKOS_FORCEINLINE_FUNCTION - typename Impl::if_c< (is_set || has_const_value), impl_value_type, impl_value_type &>::type - value_at(size_type i) const - { - return m_values[ is_set ? 0 : (i < capacity() ? i : capacity()) ]; + typename Impl::if_c<(is_set || has_const_value), impl_value_type, + impl_value_type &>::type + value_at(size_type i) const { + return m_values[is_set ? 0 : (i < capacity() ? i : capacity())]; } /// \brief Get the key with \c i as its direct index. @@ -689,138 +679,154 @@ public: /// This is a device function; it may be called in a parallel /// kernel. KOKKOS_FORCEINLINE_FUNCTION - key_type key_at(size_type i) const - { - return m_keys[ i < capacity() ? i : capacity() ]; + key_type key_at(size_type i) const { + return m_keys[i < capacity() ? i : capacity()]; } KOKKOS_FORCEINLINE_FUNCTION - bool valid_at(size_type i) const - { - return m_available_indexes.test(i); - } + bool valid_at(size_type i) const { return m_available_indexes.test(i); } template - UnorderedMap( UnorderedMap const& src, - typename Impl::enable_if< Impl::UnorderedMapCanAssign::value,int>::type = 0 - ) - : m_bounded_insert(src.m_bounded_insert) - , m_hasher(src.m_hasher) - , m_equal_to(src.m_equal_to) - , m_size(src.m_size) - , m_available_indexes(src.m_available_indexes) - , m_hash_lists(src.m_hash_lists) - , m_next_index(src.m_next_index) - , m_keys(src.m_keys) - , m_values(src.m_values) - , m_scalars(src.m_scalars) - {} - + UnorderedMap( + UnorderedMap const &src, + typename Impl::enable_if< + Impl::UnorderedMapCanAssign::value, + int>::type = 0) + : m_bounded_insert(src.m_bounded_insert), + m_hasher(src.m_hasher), + m_equal_to(src.m_equal_to), + m_size(src.m_size), + m_available_indexes(src.m_available_indexes), + m_hash_lists(src.m_hash_lists), + m_next_index(src.m_next_index), + m_keys(src.m_keys), + m_values(src.m_values), + m_scalars(src.m_scalars) {} template - typename Impl::enable_if< Impl::UnorderedMapCanAssign::value - ,declared_map_type & >::type - operator=( UnorderedMap const& src) - { - m_bounded_insert = src.m_bounded_insert; - m_hasher = src.m_hasher; - m_equal_to = src.m_equal_to; - m_size = src.m_size; + typename Impl::enable_if< + Impl::UnorderedMapCanAssign::value, + declared_map_type &>::type + operator=(UnorderedMap const &src) { + m_bounded_insert = src.m_bounded_insert; + m_hasher = src.m_hasher; + m_equal_to = src.m_equal_to; + m_size = src.m_size; m_available_indexes = src.m_available_indexes; - m_hash_lists = src.m_hash_lists; - m_next_index = src.m_next_index; - m_keys = src.m_keys; - m_values = src.m_values; - m_scalars = src.m_scalars; + m_hash_lists = src.m_hash_lists; + m_next_index = src.m_next_index; + m_keys = src.m_keys; + m_values = src.m_values; + m_scalars = src.m_scalars; return *this; } template - typename Impl::enable_if< std::is_same< typename Impl::remove_const::type, key_type>::value && - std::is_same< typename Impl::remove_const::type, value_type>::value - >::type - create_copy_view( UnorderedMap const& src) - { + typename Impl::enable_if< + std::is_same::type, key_type>::value && + std::is_same::type, + value_type>::value>::type + create_copy_view( + UnorderedMap const &src) { if (m_hash_lists.data() != src.m_hash_lists.data()) { - insertable_map_type tmp; - tmp.m_bounded_insert = src.m_bounded_insert; - tmp.m_hasher = src.m_hasher; - tmp.m_equal_to = src.m_equal_to; - tmp.m_size = src.size(); - tmp.m_available_indexes = bitset_type( src.capacity() ); - tmp.m_hash_lists = size_type_view( ViewAllocateWithoutInitializing("UnorderedMap hash list"), src.m_hash_lists.extent(0) ); - tmp.m_next_index = size_type_view( ViewAllocateWithoutInitializing("UnorderedMap next index"), src.m_next_index.extent(0) ); - tmp.m_keys = key_type_view( ViewAllocateWithoutInitializing("UnorderedMap keys"), src.m_keys.extent(0) ); - tmp.m_values = value_type_view( ViewAllocateWithoutInitializing("UnorderedMap values"), src.m_values.extent(0) ); - tmp.m_scalars = scalars_view("UnorderedMap scalars"); + tmp.m_bounded_insert = src.m_bounded_insert; + tmp.m_hasher = src.m_hasher; + tmp.m_equal_to = src.m_equal_to; + tmp.m_size = src.size(); + tmp.m_available_indexes = bitset_type(src.capacity()); + tmp.m_hash_lists = size_type_view( + ViewAllocateWithoutInitializing("UnorderedMap hash list"), + src.m_hash_lists.extent(0)); + tmp.m_next_index = size_type_view( + ViewAllocateWithoutInitializing("UnorderedMap next index"), + src.m_next_index.extent(0)); + tmp.m_keys = + key_type_view(ViewAllocateWithoutInitializing("UnorderedMap keys"), + src.m_keys.extent(0)); + tmp.m_values = value_type_view( + ViewAllocateWithoutInitializing("UnorderedMap values"), + src.m_values.extent(0)); + tmp.m_scalars = scalars_view("UnorderedMap scalars"); Kokkos::deep_copy(tmp.m_available_indexes, src.m_available_indexes); - typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, typename SDevice::memory_space > raw_deep_copy; + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; - raw_deep_copy(tmp.m_hash_lists.data(), src.m_hash_lists.data(), sizeof(size_type)*src.m_hash_lists.extent(0)); - raw_deep_copy(tmp.m_next_index.data(), src.m_next_index.data(), sizeof(size_type)*src.m_next_index.extent(0)); - raw_deep_copy(tmp.m_keys.data(), src.m_keys.data(), sizeof(key_type)*src.m_keys.extent(0)); + raw_deep_copy(tmp.m_hash_lists.data(), src.m_hash_lists.data(), + sizeof(size_type) * src.m_hash_lists.extent(0)); + raw_deep_copy(tmp.m_next_index.data(), src.m_next_index.data(), + sizeof(size_type) * src.m_next_index.extent(0)); + raw_deep_copy(tmp.m_keys.data(), src.m_keys.data(), + sizeof(key_type) * src.m_keys.extent(0)); if (!is_set) { - raw_deep_copy(tmp.m_values.data(), src.m_values.data(), sizeof(impl_value_type)*src.m_values.extent(0)); + raw_deep_copy(tmp.m_values.data(), src.m_values.data(), + sizeof(impl_value_type) * src.m_values.extent(0)); } - raw_deep_copy(tmp.m_scalars.data(), src.m_scalars.data(), sizeof(int)*num_scalars ); + raw_deep_copy(tmp.m_scalars.data(), src.m_scalars.data(), + sizeof(int) * num_scalars); *this = tmp; } } //@} -private: // private member functions + private: // private member functions + bool modified() const { return get_flag(modified_idx); } - bool modified() const - { - return get_flag(modified_idx); - } - - void set_flag(int flag) const - { - typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy; + void set_flag(int flag) const { + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; const int true_ = true; raw_deep_copy(m_scalars.data() + flag, &true_, sizeof(int)); } - void reset_flag(int flag) const - { - typedef Kokkos::Impl::DeepCopy< typename device_type::memory_space, Kokkos::HostSpace > raw_deep_copy; + void reset_flag(int flag) const { + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; const int false_ = false; raw_deep_copy(m_scalars.data() + flag, &false_, sizeof(int)); } - bool get_flag(int flag) const - { - typedef Kokkos::Impl::DeepCopy< Kokkos::HostSpace, typename device_type::memory_space > raw_deep_copy; + bool get_flag(int flag) const { + typedef Kokkos::Impl::DeepCopy + raw_deep_copy; int result = false; raw_deep_copy(&result, m_scalars.data() + flag, sizeof(int)); return result; } - static uint32_t calculate_capacity(uint32_t capacity_hint) - { + static uint32_t calculate_capacity(uint32_t capacity_hint) { // increase by 16% and round to nears multiple of 128 - return capacity_hint ? ((static_cast(7ull*capacity_hint/6u) + 127u)/128u)*128u : 128u; + return capacity_hint + ? ((static_cast(7ull * capacity_hint / 6u) + 127u) / + 128u) * + 128u + : 128u; } -private: // private members - bool m_bounded_insert; - hasher_type m_hasher; - equal_to_type m_equal_to; + private: // private members + bool m_bounded_insert; + hasher_type m_hasher; + equal_to_type m_equal_to; mutable size_type m_size; - bitset_type m_available_indexes; - size_type_view m_hash_lists; - size_type_view m_next_index; - key_type_view m_keys; - value_type_view m_values; - scalars_view m_scalars; - - template + bitset_type m_available_indexes; + size_type_view m_hash_lists; + size_type_view m_next_index; + key_type_view m_keys; + value_type_view m_values; + scalars_view m_scalars; + + template friend class UnorderedMap; template @@ -834,17 +840,14 @@ private: // private members }; // Specialization of deep_copy for two UnorderedMap objects. -template < typename DKey, typename DT, typename DDevice - , typename SKey, typename ST, typename SDevice - , typename Hasher, typename EqualTo > -inline void deep_copy( UnorderedMap & dst - , const UnorderedMap & src ) -{ +template +inline void deep_copy( + UnorderedMap &dst, + const UnorderedMap &src) { dst.create_copy_view(src); } +} // namespace Kokkos -} // namespace Kokkos - -#endif //KOKKOS_UNORDERED_MAP_HPP - +#endif // KOKKOS_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/src/Kokkos_Vector.hpp b/lib/kokkos/containers/src/Kokkos_Vector.hpp index a44d1f58b5..8962485abe 100644 --- a/lib/kokkos/containers/src/Kokkos_Vector.hpp +++ b/lib/kokkos/containers/src/Kokkos_Vector.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,15 +49,15 @@ #include /* Drop in replacement for std::vector based on Kokkos::DualView - * Most functions only work on the host (it will not compile if called from device kernel) + * Most functions only work on the host (it will not compile if called from + * device kernel) * */ - namespace Kokkos { +namespace Kokkos { -template< class Scalar, class Arg1Type = void> -class vector : public DualView { - -public: +template +class vector : public DualView { + public: typedef Scalar value_type; typedef Scalar* pointer; typedef const Scalar* const_pointer; @@ -64,213 +65,259 @@ public: typedef const Scalar& const_reference; typedef Scalar* iterator; typedef const Scalar* const_iterator; + typedef size_t size_type; -private: + private: size_t _size; - typedef size_t size_type; float _extra_storage; - typedef DualView DV; + typedef DualView DV; - -public: + public: #ifdef KOKKOS_ENABLE_CUDA_UVM - KOKKOS_INLINE_FUNCTION reference operator() (int i) const {return DV::h_view(i);}; - KOKKOS_INLINE_FUNCTION reference operator[] (int i) const {return DV::h_view(i);}; + KOKKOS_INLINE_FUNCTION reference operator()(int i) const { + return DV::h_view(i); + }; + KOKKOS_INLINE_FUNCTION reference operator[](int i) const { + return DV::h_view(i); + }; #else - inline reference operator() (int i) const {return DV::h_view(i);}; - inline reference operator[] (int i) const {return DV::h_view(i);}; + inline reference operator()(int i) const { return DV::h_view(i); }; + inline reference operator[](int i) const { return DV::h_view(i); }; #endif /* Member functions which behave like std::vector functions */ - vector():DV() { - _size = 0; + vector() : DV() { + _size = 0; _extra_storage = 1.1; } - - vector(int n, Scalar val=Scalar()):DualView("Vector",size_t(n*(1.1))) { - _size = n; - _extra_storage = 1.1; + vector(int n, Scalar val = Scalar()) + : DualView("Vector", size_t(n * (1.1))) { + _size = n; + _extra_storage = 1.1; DV::modified_flags(0) = 1; - assign(n,val); + assign(n, val); } - void resize(size_t n) { - if(n>=span()) - DV::resize(size_t (n*_extra_storage)); + if (n >= span()) DV::resize(size_t(n * _extra_storage)); _size = n; } - void resize(size_t n, const Scalar& val) { - assign(n,val); - } - - void assign (size_t n, const Scalar& val) { + void resize(size_t n, const Scalar& val) { assign(n, val); } - /* Resize if necessary (behavior of std:vector) */ + void assign(size_t n, const Scalar& val) { + /* Resize if necessary (behavour of std:vector) */ - if(n>span()) - DV::resize(size_t (n*_extra_storage)); + if (n > span()) DV::resize(size_t(n * _extra_storage)); _size = n; - /* Assign value either on host or on device */ + /* Assign value either on host or on device */ - if( DV::template need_sync() ) { - set_functor_host f(DV::h_view,val); - parallel_for(n,f); + if (DV::template need_sync()) { + set_functor_host f(DV::h_view, val); + parallel_for(n, f); typename DV::t_host::execution_space().fence(); DV::template modify(); } else { - set_functor f(DV::d_view,val); - parallel_for(n,f); + set_functor f(DV::d_view, val); + parallel_for(n, f); typename DV::t_dev::execution_space().fence(); DV::template modify(); } } - void reserve(size_t n) { - DV::resize(size_t (n*_extra_storage)); - } + void reserve(size_t n) { DV::resize(size_t(n * _extra_storage)); } void push_back(Scalar val) { DV::template sync(); DV::template modify(); - if(_size == span()) { - size_t new_size = _size*_extra_storage; - if(new_size == _size) new_size++; + if (_size == span()) { + size_t new_size = _size * _extra_storage; + if (new_size == _size) new_size++; DV::resize(new_size); } DV::h_view(_size) = val; _size++; + } + + void pop_back() { _size--; } + void clear() { _size = 0; } + + iterator insert(iterator it, const value_type& val) { + return insert(it, 1, val); } - void pop_back() { - _size--; + iterator insert(iterator it, size_type count, const value_type& val) { + if ((size() == 0) && (it == begin())) { + resize(count, val); + DV::sync_host(); + return begin(); + } + DV::sync_host(); + DV::modify_host(); + if (it < begin() || it > end()) + Kokkos::abort("Kokkos::vector::insert : invalid insert iterator"); + if (count == 0) return it; + ptrdiff_t start = std::distance(begin(), it); + auto org_size = size(); + resize(size() + count); + + std::copy_backward(begin() + start, begin() + org_size, + begin() + org_size + count); + std::fill_n(begin() + start, count, val); + + return begin() + start; } - void clear() { - _size = 0; + private: + template + struct impl_is_input_iterator + : /* TODO replace this */ std::integral_constant< + bool, !std::is_convertible::value> {}; + + public: + // TODO: can use detection idiom to generate better error message here later + template + typename std::enable_if::value, + iterator>::type + insert(iterator it, InputIterator b, InputIterator e) { + ptrdiff_t count = std::distance(b, e); + if (count == 0) return it; + + DV::sync_host(); + DV::modify_host(); + if (it < begin() || it > end()) + Kokkos::abort("Kokkos::vector::insert : invalid insert iterator"); + + bool resized = false; + if ((size() == 0) && (it == begin())) { + resize(count); + it = begin(); + resized = true; + } + ptrdiff_t start = std::distance(begin(), it); + auto org_size = size(); + if (!resized) resize(size() + count); + it = begin() + start; + + std::copy_backward(begin() + start, begin() + org_size, + begin() + org_size + count); + std::copy(b, e, it); + + return begin() + start; } - size_type size() const {return _size;} - size_type max_size() const {return 2000000000;} + size_type size() const { return _size; } + size_type max_size() const { return 2000000000; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - size_type capacity() const {return DV::capacity();} + size_type capacity() const { return DV::capacity(); } #endif - size_type span() const {return DV::span();} - bool empty() const {return _size==0;} + size_type span() const { return DV::span(); } + bool empty() const { return _size == 0; } - iterator begin() const {return &DV::h_view(0);} + iterator begin() const { return DV::h_view.data(); } - iterator end() const {return &DV::h_view(_size);} + iterator end() const { + return _size > 0 ? DV::h_view.data() + _size : DV::h_view.data(); + } - reference front() {return DV::h_view(0);} + reference front() { return DV::h_view(0); } - reference back() {return DV::h_view(_size - 1);} + reference back() { return DV::h_view(_size - 1); } - const_reference front() const {return DV::h_view(0);} + const_reference front() const { return DV::h_view(0); } - const_reference back() const {return DV::h_view(_size - 1);} + const_reference back() const { return DV::h_view(_size - 1); } - /* std::algorithms which work originally with iterators, here they are implemented as member functions */ + /* std::algorithms wich work originally with iterators, here they are + * implemented as member functions */ - size_t - lower_bound (const size_t& start, - const size_t& theEnd, - const Scalar& comp_val) const - { - int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion - int upper = _size > theEnd? theEnd : _size-1; // FIXME (mfh 24 Apr 2014) narrowing conversion + size_t lower_bound(const size_t& start, const size_t& theEnd, + const Scalar& comp_val) const { + int lower = start; // FIXME (mfh 24 Apr 2014) narrowing conversion + int upper = + _size > theEnd + ? theEnd + : _size - 1; // FIXME (mfh 24 Apr 2014) narrowing conversion if (upper <= lower) { return theEnd; } Scalar lower_val = DV::h_view(lower); Scalar upper_val = DV::h_view(upper); - size_t idx = (upper+lower)/2; - Scalar val = DV::h_view(idx); - if(val>upper_val) return upper; - if(val upper_val) return upper; + if (val < lower_val) return start; - while(upper>lower) { - if(comp_val>val) { + while (upper > lower) { + if (comp_val > val) { lower = ++idx; } else { upper = idx; } - idx = (upper+lower)/2; + idx = (upper + lower) / 2; val = DV::h_view(idx); } return idx; } bool is_sorted() { - for(int i=0;i<_size-1;i++) { - if(DV::h_view(i)>DV::h_view(i+1)) return false; + for (int i = 0; i < _size - 1; i++) { + if (DV::h_view(i) > DV::h_view(i + 1)) return false; } return true; } iterator find(Scalar val) const { - if(_size == 0) return end(); + if (_size == 0) return end(); - int upper,lower,current; - current = _size/2; - upper = _size-1; - lower = 0; + int upper, lower, current; + current = _size / 2; + upper = _size - 1; + lower = 0; - if((valDV::h_view(_size-1)) ) return end(); + if ((val < DV::h_view(0)) || (val > DV::h_view(_size - 1))) return end(); - while(upper>lower) - { - if(val>DV::h_view(current)) lower = current+1; - else upper = current; - current = (upper+lower)/2; + while (upper > lower) { + if (val > DV::h_view(current)) + lower = current + 1; + else + upper = current; + current = (upper + lower) / 2; } - if(val==DV::h_view(current)) return &DV::h_view(current); - else return end(); + if (val == DV::h_view(current)) + return &DV::h_view(current); + else + return end(); } /* Additional functions for data management */ - void device_to_host(){ - deep_copy(DV::h_view,DV::d_view); - } - void host_to_device() const { - deep_copy(DV::d_view,DV::h_view); - } - - void on_host() { - DV::template modify(); - } - void on_device() { - DV::template modify(); - } + void device_to_host() { deep_copy(DV::h_view, DV::d_view); } + void host_to_device() const { deep_copy(DV::d_view, DV::h_view); } - void set_overallocation(float extra) { - _extra_storage = 1.0 + extra; - } + void on_host() { DV::template modify(); } + void on_device() { DV::template modify(); } + void set_overallocation(float extra) { _extra_storage = 1.0 + extra; } -public: + public: struct set_functor { typedef typename DV::t_dev::execution_space execution_space; typename DV::t_dev _data; Scalar _val; - set_functor(typename DV::t_dev data, Scalar val) : - _data(data),_val(val) {} + set_functor(typename DV::t_dev data, Scalar val) : _data(data), _val(val) {} KOKKOS_INLINE_FUNCTION - void operator() (const int &i) const { - _data(i) = _val; - } + void operator()(const int& i) const { _data(i) = _val; } }; struct set_functor_host { @@ -278,18 +325,13 @@ public: typename DV::t_host _data; Scalar _val; - set_functor_host(typename DV::t_host data, Scalar val) : - _data(data),_val(val) {} + set_functor_host(typename DV::t_host data, Scalar val) + : _data(data), _val(val) {} KOKKOS_INLINE_FUNCTION - void operator() (const int &i) const { - _data(i) = _val; - } + void operator()(const int& i) const { _data(i) = _val; } }; - }; - -} +} // namespace Kokkos #endif - diff --git a/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp b/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp index 7ea2e102ce..f5fa4d518a 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_Bitset_impl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,53 +58,44 @@ namespace Kokkos { namespace Impl { KOKKOS_FORCEINLINE_FUNCTION -unsigned rotate_right( unsigned i, int r ) -{ - enum { size = static_cast( sizeof(unsigned) * CHAR_BIT ) }; - return r ? ( ( i >> r ) | ( i << ( size - r ) ) ) : i ; +unsigned rotate_right(unsigned i, int r) { + enum { size = static_cast(sizeof(unsigned) * CHAR_BIT) }; + return r ? ((i >> r) | (i << (size - r))) : i; } -template < typename Bitset > -struct BitsetCount -{ - typedef Bitset bitset_type; - typedef typename bitset_type::execution_space::execution_space execution_space; - typedef typename bitset_type::size_type size_type; - typedef size_type value_type; +template +struct BitsetCount { + typedef Bitset bitset_type; + typedef + typename bitset_type::execution_space::execution_space execution_space; + typedef typename bitset_type::size_type size_type; + typedef size_type value_type; bitset_type m_bitset; - BitsetCount( bitset_type const& bitset ) - : m_bitset(bitset) - {} + BitsetCount(bitset_type const& bitset) : m_bitset(bitset) {} - size_type apply() const - { + size_type apply() const { size_type count = 0u; - parallel_reduce( m_bitset.m_blocks.extent(0), *this, count ); + parallel_reduce(m_bitset.m_blocks.extent(0), *this, count); return count; } KOKKOS_INLINE_FUNCTION - void init( value_type & count ) const - { - count = 0u; - } + void init(value_type& count) const { count = 0u; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & count, const volatile size_type & incr ) const - { + void join(volatile value_type& count, const volatile size_type& incr) const { count += incr; } KOKKOS_INLINE_FUNCTION - void operator()( size_type i, value_type & count ) const - { - count += bit_count( m_bitset.m_blocks[i] ); + void operator()(size_type i, value_type& count) const { + count += bit_count(m_bitset.m_blocks[i]); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos -#endif // KOKKOS_BITSET_IMPL_HPP +#endif // KOKKOS_BITSET_IMPL_HPP diff --git a/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp b/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp index 8b17dcce4b..6ba67766aa 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_Functional_impl.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,28 +46,24 @@ #include #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { // MurmurHash3 was written by Austin Appleby, and is placed in the public // domain. The author hereby disclaims copyright to this source code. KOKKOS_FORCEINLINE_FUNCTION -uint32_t getblock32 ( const uint8_t * p, int i ) -{ -// used to avoid aliasing error which could cause errors with -// forced inlining - return ((uint32_t)p[i*4+0]) - | ((uint32_t)p[i*4+1] << 8) - | ((uint32_t)p[i*4+2] << 16) - | ((uint32_t)p[i*4+3] << 24); +uint32_t getblock32(const uint8_t* p, int i) { + // used to avoid aliasing error which could cause errors with + // forced inlining + return ((uint32_t)p[i * 4 + 0]) | ((uint32_t)p[i * 4 + 1] << 8) | + ((uint32_t)p[i * 4 + 2] << 16) | ((uint32_t)p[i * 4 + 3] << 24); } KOKKOS_FORCEINLINE_FUNCTION -uint32_t rotl32 ( uint32_t x, int8_t r ) -{ return (x << r) | (x >> (32 - r)); } +uint32_t rotl32(uint32_t x, int8_t r) { return (x << r) | (x >> (32 - r)); } KOKKOS_FORCEINLINE_FUNCTION -uint32_t fmix32 ( uint32_t h ) -{ +uint32_t fmix32(uint32_t h) { h ^= h >> 16; h *= 0x85ebca6b; h ^= h >> 13; @@ -77,10 +74,9 @@ uint32_t fmix32 ( uint32_t h ) } KOKKOS_INLINE_FUNCTION -uint32_t MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 4; +uint32_t MurmurHash3_x86_32(const void* key, int len, uint32_t seed) { + const uint8_t* data = (const uint8_t*)key; + const int nblocks = len / 4; uint32_t h1 = seed; @@ -90,32 +86,34 @@ uint32_t MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed ) //---------- // body - for(int i=0; i -KOKKOS_FORCEINLINE_FUNCTION -bool bitwise_equal(T const * const a_ptr, T const * const b_ptr) -{ +KOKKOS_FORCEINLINE_FUNCTION bool bitwise_equal(T const* const a_ptr, + T const* const b_ptr) { typedef uint64_t KOKKOS_IMPL_MAY_ALIAS T64; typedef uint32_t KOKKOS_IMPL_MAY_ALIAS T32; typedef uint16_t KOKKOS_IMPL_MAY_ALIAS T16; - typedef uint8_t KOKKOS_IMPL_MAY_ALIAS T8; + typedef uint8_t KOKKOS_IMPL_MAY_ALIAS T8; enum { NUM_8 = sizeof(T), @@ -158,39 +153,37 @@ bool bitwise_equal(T const * const a_ptr, T const * const b_ptr) }; union { - T const * const ptr; - T64 const * const ptr64; - T32 const * const ptr32; - T16 const * const ptr16; - T8 const * const ptr8; + T const* const ptr; + T64 const* const ptr64; + T32 const* const ptr32; + T16 const* const ptr16; + T8 const* const ptr8; } a = {a_ptr}, b = {b_ptr}; bool result = true; - for (int i=0; i < NUM_64; ++i) { + for (int i = 0; i < NUM_64; ++i) { result = result && a.ptr64[i] == b.ptr64[i]; } - if ( NUM_64*2 < NUM_32 ) { - result = result && a.ptr32[NUM_64*2] == b.ptr32[NUM_64*2]; + if (NUM_64 * 2 < NUM_32) { + result = result && a.ptr32[NUM_64 * 2] == b.ptr32[NUM_64 * 2]; } - if ( NUM_32*2 < NUM_16 ) { - result = result && a.ptr16[NUM_32*2] == b.ptr16[NUM_32*2]; + if (NUM_32 * 2 < NUM_16) { + result = result && a.ptr16[NUM_32 * 2] == b.ptr16[NUM_32 * 2]; } - if ( NUM_16*2 < NUM_8 ) { - result = result && a.ptr8[NUM_16*2] == b.ptr8[NUM_16*2]; + if (NUM_16 * 2 < NUM_8) { + result = result && a.ptr8[NUM_16 * 2] == b.ptr8[NUM_16 * 2]; } return result; } - - #undef KOKKOS_IMPL_MAY_ALIAS -}} // namespace Kokkos::Impl - -#endif //KOKKOS_FUNCTIONAL_IMPL_HPP +} // namespace Impl +} // namespace Kokkos +#endif // KOKKOS_FUNCTIONAL_IMPL_HPP diff --git a/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp b/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp index 743c345b45..d644c57c0a 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_StaticCrsGraph_factory.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -50,193 +51,207 @@ namespace Kokkos { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -template< class DataType , class Arg1Type , class Arg2Type , typename SizeType , class Arg3Type> -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ViewTraits::is_hostspace >::type * = 0 ) -{ - return view ; +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) { + return view; } #else -template< class DataType , class Arg1Type , class Arg2Type , class Arg3Type, typename SizeType > -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ViewTraits::is_hostspace >::type * = 0 ) -{ - return view ; +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) { + return view; } #endif #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -template< class DataType , class Arg1Type , class Arg2Type , typename SizeType , class Arg3Type> -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type >::HostMirror -create_mirror( const StaticCrsGraph & view ) -{ +template +inline typename StaticCrsGraph::HostMirror +create_mirror(const StaticCrsGraph& view) { // Force copy: - //typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused - typedef StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type > staticcrsgraph_type ; + // typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused + typedef StaticCrsGraph + staticcrsgraph_type; #else -template< class DataType , class Arg1Type , class Arg2Type , class Arg3Type, typename SizeType > -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType >::HostMirror -create_mirror( const StaticCrsGraph & view ) -{ +template +inline typename StaticCrsGraph::HostMirror +create_mirror(const StaticCrsGraph& view) { // Force copy: - //typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused - typedef StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType > staticcrsgraph_type ; + // typedef Impl::ViewAssignment< Impl::ViewDefault > alloc ; // unused + typedef StaticCrsGraph + staticcrsgraph_type; #endif - typename staticcrsgraph_type::HostMirror tmp ; - typename staticcrsgraph_type::row_map_type::HostMirror tmp_row_map = create_mirror( view.row_map); - typename staticcrsgraph_type::row_block_type::HostMirror tmp_row_block_offsets = create_mirror( view.row_block_offsets); + typename staticcrsgraph_type::HostMirror tmp; + typename staticcrsgraph_type::row_map_type::HostMirror tmp_row_map = + create_mirror(view.row_map); + typename staticcrsgraph_type::row_block_type::HostMirror + tmp_row_block_offsets = create_mirror(view.row_block_offsets); // Allocation to match: - tmp.row_map = tmp_row_map ; // Assignment of 'const' from 'non-const' - tmp.entries = create_mirror( view.entries ); - tmp.row_block_offsets = tmp_row_block_offsets ; // Assignment of 'const' from 'non-const' + tmp.row_map = tmp_row_map; // Assignment of 'const' from 'non-const' + tmp.entries = create_mirror(view.entries); + tmp.row_block_offsets = + tmp_row_block_offsets; // Assignment of 'const' from 'non-const' // Deep copy: - deep_copy( tmp_row_map , view.row_map ); - deep_copy( tmp.entries , view.entries ); - deep_copy( tmp_row_block_offsets , view.row_block_offsets ); + deep_copy(tmp_row_map, view.row_map); + deep_copy(tmp.entries, view.entries); + deep_copy(tmp_row_block_offsets, view.row_block_offsets); - return tmp ; + return tmp; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -template< class DataType , class Arg1Type , class Arg2Type , typename SizeType , class Arg3Type> -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , SizeType , Arg3Type >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ! ViewTraits::is_hostspace >::type * = 0 ) +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) #else -template< class DataType , class Arg1Type , class Arg2Type , class Arg3Type, typename SizeType > -inline -typename StaticCrsGraph< DataType , Arg1Type , Arg2Type , Arg3Type , SizeType >::HostMirror -create_mirror_view( const StaticCrsGraph & view , - typename Impl::enable_if< ! ViewTraits::is_hostspace >::type * = 0 ) +template +inline typename StaticCrsGraph::HostMirror +create_mirror_view( + const StaticCrsGraph& + view, + typename Impl::enable_if::is_hostspace>::type* = 0) #endif { - return create_mirror( view ); + return create_mirror(view); } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -template< class StaticCrsGraphType , class InputSizeType > -inline -typename StaticCrsGraphType::staticcrsgraph_type -create_staticcrsgraph( const std::string & label , - const std::vector< InputSizeType > & input ) -{ - typedef StaticCrsGraphType output_type ; - //typedef std::vector< InputSizeType > input_type ; // unused +template +inline typename StaticCrsGraphType::staticcrsgraph_type create_staticcrsgraph( + const std::string& label, const std::vector& input) { + typedef StaticCrsGraphType output_type; + // typedef std::vector< InputSizeType > input_type ; // unused - typedef typename output_type::entries_type entries_type ; + typedef typename output_type::entries_type entries_type; - typedef View< typename output_type::size_type [] , - typename output_type::array_layout , - typename output_type::execution_space, - typename output_type::memory_traits > work_type ; + typedef View + work_type; - output_type output ; + output_type output; // Create the row map: const size_t length = input.size(); { - work_type row_work( "tmp" , length + 1 ); + work_type row_work("tmp", length + 1); - typename work_type::HostMirror row_work_host = - create_mirror_view( row_work ); + typename work_type::HostMirror row_work_host = create_mirror_view(row_work); - size_t sum = 0 ; - row_work_host[0] = 0 ; - for ( size_t i = 0 ; i < length ; ++i ) { - row_work_host[i+1] = sum += input[i]; + size_t sum = 0; + row_work_host[0] = 0; + for (size_t i = 0; i < length; ++i) { + row_work_host[i + 1] = sum += input[i]; } - deep_copy( row_work , row_work_host ); + deep_copy(row_work, row_work_host); - output.entries = entries_type( label , sum ); - output.row_map = row_work ; + output.entries = entries_type(label, sum); + output.row_map = row_work; } - return output ; + return output; } //---------------------------------------------------------------------------- -template< class StaticCrsGraphType , class InputSizeType > -inline -typename StaticCrsGraphType::staticcrsgraph_type -create_staticcrsgraph( const std::string & label , - const std::vector< std::vector< InputSizeType > > & input ) -{ - typedef StaticCrsGraphType output_type ; - typedef typename output_type::entries_type entries_type ; +template +inline typename StaticCrsGraphType::staticcrsgraph_type create_staticcrsgraph( + const std::string& label, + const std::vector >& input) { + typedef StaticCrsGraphType output_type; + typedef typename output_type::entries_type entries_type; - static_assert( entries_type::rank == 1 - , "Graph entries view must be rank one" ); + static_assert(entries_type::rank == 1, "Graph entries view must be rank one"); - typedef View< typename output_type::size_type [] , - typename output_type::array_layout , - typename output_type::execution_space, - typename output_type::memory_traits > work_type ; + typedef View + work_type; - output_type output ; + output_type output; - // Create the row map: + // Create the row map: const size_t length = input.size(); { - work_type row_work( "tmp" , length + 1 ); + work_type row_work("tmp", length + 1); - typename work_type::HostMirror row_work_host = - create_mirror_view( row_work ); + typename work_type::HostMirror row_work_host = create_mirror_view(row_work); - size_t sum = 0 ; - row_work_host[0] = 0 ; - for ( size_t i = 0 ; i < length ; ++i ) { - row_work_host[i+1] = sum += input[i].size(); + size_t sum = 0; + row_work_host[0] = 0; + for (size_t i = 0; i < length; ++i) { + row_work_host[i + 1] = sum += input[i].size(); } - deep_copy( row_work , row_work_host ); + deep_copy(row_work, row_work_host); - output.entries = entries_type( label , sum ); - output.row_map = row_work ; + output.entries = entries_type(label, sum); + output.row_map = row_work; } // Fill in the entries: { typename entries_type::HostMirror host_entries = - create_mirror_view( output.entries ); + create_mirror_view(output.entries); - size_t sum = 0 ; - for ( size_t i = 0 ; i < length ; ++i ) { - for ( size_t j = 0 ; j < input[i].size() ; ++j , ++sum ) { - host_entries( sum ) = input[i][j] ; + size_t sum = 0; + for (size_t i = 0; i < length; ++i) { + for (size_t j = 0; j < input[i].size(); ++j, ++sum) { + host_entries(sum) = input[i][j]; } } - deep_copy( output.entries , host_entries ); + deep_copy(output.entries, host_entries); } - return output ; + return output; } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #ifndef KOKKOS_IMPL_CRSARRAY_FACTORY_HPP */ - diff --git a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp index 88ca200daf..e10e256b6a 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp +++ b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.cpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,58 +37,62 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { -uint32_t find_hash_size(uint32_t size) -{ +uint32_t find_hash_size(uint32_t size) { if (size == 0u) return 0u; // these primes try to preserve randomness of hash - static const uint32_t primes [] = { - 3, 7, 13, 23, 53, 97, 193, 389, 769, 1543 - , 2237, 2423, 2617, 2797, 2999, 3167, 3359, 3539 - , 3727, 3911, 4441 , 4787 , 5119 , 5471 , 5801 , 6143 , 6521 , 6827 - , 7177 , 7517 , 7853 , 8887 , 9587 , 10243 , 10937 , 11617 , 12289 - , 12967 , 13649 , 14341 , 15013 , 15727 - , 17749 , 19121 , 20479 , 21859 , 23209 , 24593 , 25939 , 27329 - , 28669 , 30047 , 31469 , 35507 , 38231 , 40961 , 43711 , 46439 - , 49157 , 51893 , 54617 , 57347 , 60077 , 62801 , 70583 , 75619 - , 80669 , 85703 , 90749 , 95783 , 100823 , 105871 , 110909 , 115963 - , 120997 , 126031 , 141157 , 151237 , 161323 , 171401 , 181499 , 191579 - , 201653 , 211741 , 221813 , 231893 , 241979 , 252079 - , 282311 , 302483 , 322649 , 342803 , 362969 , 383143 , 403301 , 423457 - , 443629 , 463787 , 483953 , 504121 , 564617 , 604949 , 645313 , 685609 - , 725939 , 766273 , 806609 , 846931 , 887261 , 927587 , 967919 , 1008239 - , 1123477 , 1198397 , 1273289 , 1348177 , 1423067 , 1497983 , 1572869 - , 1647761 , 1722667 , 1797581 , 1872461 , 1947359 , 2022253 - , 2246953 , 2396759 , 2546543 , 2696363 , 2846161 , 2995973 , 3145739 - , 3295541 , 3445357 , 3595117 , 3744941 , 3894707 , 4044503 - , 4493921 , 4793501 , 5093089 , 5392679 , 5692279 , 5991883 , 6291469 - , 6591059 , 6890641 , 7190243 , 7489829 , 7789447 , 8089033 - , 8987807 , 9586981 , 10186177 , 10785371 , 11384539 , 11983729 - , 12582917 , 13182109 , 13781291 , 14380469 , 14979667 , 15578861 - , 16178053 , 17895707 , 19014187 , 20132683 , 21251141 , 22369661 - , 23488103 , 24606583 , 25725083 , 26843549 , 27962027 , 29080529 - , 30198989 , 31317469 , 32435981 , 35791397 , 38028379 , 40265327 - , 42502283 , 44739259 , 46976221 , 49213237 , 51450131 , 53687099 - , 55924061 , 58161041 , 60397993 , 62634959 , 64871921 - , 71582857 , 76056727 , 80530643 , 85004567 , 89478503 , 93952427 - , 98426347 , 102900263 , 107374217 , 111848111 , 116322053 , 120795971 - , 125269877 , 129743807 , 143165587 , 152113427 , 161061283 , 170009141 - , 178956983 , 187904819 , 196852693 , 205800547 , 214748383 , 223696237 - , 232644089 , 241591943 , 250539763 , 259487603 , 268435399 - }; + static const uint32_t primes[] = { + 3, 7, 13, 23, 53, 97, + 193, 389, 769, 1543, 2237, 2423, + 2617, 2797, 2999, 3167, 3359, 3539, + 3727, 3911, 4441, 4787, 5119, 5471, + 5801, 6143, 6521, 6827, 7177, 7517, + 7853, 8887, 9587, 10243, 10937, 11617, + 12289, 12967, 13649, 14341, 15013, 15727, + 17749, 19121, 20479, 21859, 23209, 24593, + 25939, 27329, 28669, 30047, 31469, 35507, + 38231, 40961, 43711, 46439, 49157, 51893, + 54617, 57347, 60077, 62801, 70583, 75619, + 80669, 85703, 90749, 95783, 100823, 105871, + 110909, 115963, 120997, 126031, 141157, 151237, + 161323, 171401, 181499, 191579, 201653, 211741, + 221813, 231893, 241979, 252079, 282311, 302483, + 322649, 342803, 362969, 383143, 403301, 423457, + 443629, 463787, 483953, 504121, 564617, 604949, + 645313, 685609, 725939, 766273, 806609, 846931, + 887261, 927587, 967919, 1008239, 1123477, 1198397, + 1273289, 1348177, 1423067, 1497983, 1572869, 1647761, + 1722667, 1797581, 1872461, 1947359, 2022253, 2246953, + 2396759, 2546543, 2696363, 2846161, 2995973, 3145739, + 3295541, 3445357, 3595117, 3744941, 3894707, 4044503, + 4493921, 4793501, 5093089, 5392679, 5692279, 5991883, + 6291469, 6591059, 6890641, 7190243, 7489829, 7789447, + 8089033, 8987807, 9586981, 10186177, 10785371, 11384539, + 11983729, 12582917, 13182109, 13781291, 14380469, 14979667, + 15578861, 16178053, 17895707, 19014187, 20132683, 21251141, + 22369661, 23488103, 24606583, 25725083, 26843549, 27962027, + 29080529, 30198989, 31317469, 32435981, 35791397, 38028379, + 40265327, 42502283, 44739259, 46976221, 49213237, 51450131, + 53687099, 55924061, 58161041, 60397993, 62634959, 64871921, + 71582857, 76056727, 80530643, 85004567, 89478503, 93952427, + 98426347, 102900263, 107374217, 111848111, 116322053, 120795971, + 125269877, 129743807, 143165587, 152113427, 161061283, 170009141, + 178956983, 187904819, 196852693, 205800547, 214748383, 223696237, + 232644089, 241591943, 250539763, 259487603, 268435399}; - const uint32_t num_primes = sizeof(primes)/sizeof(uint32_t); + const uint32_t num_primes = sizeof(primes) / sizeof(uint32_t); - uint32_t hsize = primes[num_primes-1] ; + uint32_t hsize = primes[num_primes - 1]; for (uint32_t i = 0; i < num_primes; ++i) { if (size <= primes[i]) { hsize = primes[i]; @@ -97,5 +102,5 @@ uint32_t find_hash_size(uint32_t size) return hsize; } -}} // namespace Kokkos::Impl - +} // namespace Impl +} // namespace Kokkos diff --git a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp index f97c1fc046..55e76c424d 100644 --- a/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp +++ b/lib/kokkos/containers/src/impl/Kokkos_UnorderedMap_impl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,42 +53,34 @@ #include #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { -uint32_t find_hash_size( uint32_t size ); +uint32_t find_hash_size(uint32_t size); template -struct UnorderedMapRehash -{ +struct UnorderedMapRehash { typedef Map map_type; typedef typename map_type::const_map_type const_map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; - map_type m_dst; + map_type m_dst; const_map_type m_src; - UnorderedMapRehash( map_type const& dst, const_map_type const& src) - : m_dst(dst), m_src(src) - {} + UnorderedMapRehash(map_type const& dst, const_map_type const& src) + : m_dst(dst), m_src(src) {} - void apply() const - { - parallel_for(m_src.capacity(), *this); - } + void apply() const { parallel_for(m_src.capacity(), *this); } KOKKOS_INLINE_FUNCTION - void operator()(size_type i) const - { - if ( m_src.valid_at(i) ) - m_dst.insert(m_src.key_at(i), m_src.value_at(i)); + void operator()(size_type i) const { + if (m_src.valid_at(i)) m_dst.insert(m_src.key_at(i), m_src.value_at(i)); } - }; template -struct UnorderedMapErase -{ +struct UnorderedMapErase { typedef UMap map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; @@ -96,18 +89,12 @@ struct UnorderedMapErase map_type m_map; - UnorderedMapErase( map_type const& map) - : m_map(map) - {} + UnorderedMapErase(map_type const& map) : m_map(map) {} - void apply() const - { - parallel_for(m_map.m_hash_lists.extent(0), *this); - } + void apply() const { parallel_for(m_map.m_hash_lists.extent(0), *this); } KOKKOS_INLINE_FUNCTION - void operator()( size_type i ) const - { + void operator()(size_type i) const { const size_type invalid_index = map_type::invalid_index; size_type curr = m_map.m_hash_lists(i); @@ -115,29 +102,28 @@ struct UnorderedMapErase // remove erased head of the linked-list while (curr != invalid_index && !m_map.valid_at(curr)) { - next = m_map.m_next_index[curr]; + next = m_map.m_next_index[curr]; m_map.m_next_index[curr] = invalid_index; - m_map.m_keys[curr] = key_type(); + m_map.m_keys[curr] = key_type(); if (m_map.is_set) m_map.m_values[curr] = value_type(); - curr = next; + curr = next; m_map.m_hash_lists(i) = next; } // if the list is non-empty and the head is valid - if (curr != invalid_index && m_map.valid_at(curr) ) { + if (curr != invalid_index && m_map.valid_at(curr)) { size_type prev = curr; - curr = m_map.m_next_index[prev]; + curr = m_map.m_next_index[prev]; while (curr != invalid_index) { next = m_map.m_next_index[curr]; if (m_map.valid_at(curr)) { prev = curr; - } - else { + } else { // remove curr from list m_map.m_next_index[prev] = next; m_map.m_next_index[curr] = invalid_index; - m_map.m_keys[curr] = key_type(); + m_map.m_keys[curr] = key_type(); if (map_type::is_set) m_map.m_values[curr] = value_type(); } curr = next; @@ -147,8 +133,7 @@ struct UnorderedMapErase }; template -struct UnorderedMapHistogram -{ +struct UnorderedMapHistogram { typedef UMap map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; @@ -161,117 +146,100 @@ struct UnorderedMapHistogram histogram_view m_distance; histogram_view m_block_distance; - UnorderedMapHistogram( map_type const& map) - : m_map(map) - , m_length("UnorderedMap Histogram") - , m_distance("UnorderedMap Histogram") - , m_block_distance("UnorderedMap Histogram") - {} + UnorderedMapHistogram(map_type const& map) + : m_map(map), + m_length("UnorderedMap Histogram"), + m_distance("UnorderedMap Histogram"), + m_block_distance("UnorderedMap Histogram") {} - void calculate() - { - parallel_for(m_map.m_hash_lists.extent(0), *this); - } + void calculate() { parallel_for(m_map.m_hash_lists.extent(0), *this); } - void clear() - { + void clear() { Kokkos::deep_copy(m_length, 0); Kokkos::deep_copy(m_distance, 0); Kokkos::deep_copy(m_block_distance, 0); } - void print_length(std::ostream &out) - { + void print_length(std::ostream& out) { host_histogram_view host_copy = create_mirror_view(m_length); Kokkos::deep_copy(host_copy, m_length); - for (int i=0, size = host_copy.extent(0); i -struct UnorderedMapPrint -{ +struct UnorderedMapPrint { typedef UMap map_type; typedef typename map_type::execution_space execution_space; typedef typename map_type::size_type size_type; map_type m_map; - UnorderedMapPrint( map_type const& map) - : m_map(map) - {} + UnorderedMapPrint(map_type const& map) : m_map(map) {} - void apply() - { - parallel_for(m_map.m_hash_lists.extent(0), *this); - } + void apply() { parallel_for(m_map.m_hash_lists.extent(0), *this); } KOKKOS_INLINE_FUNCTION - void operator()( size_type i ) const - { + void operator()(size_type i) const { const size_type invalid_index = map_type::invalid_index; uint32_t list = m_map.m_hash_lists(i); - for (size_type curr = list, ii=0; curr != invalid_index; curr = m_map.m_next_index[curr], ++ii) { - printf("%d[%d]: %d->%d\n", list, ii, m_map.key_at(curr), m_map.value_at(curr)); + for (size_type curr = list, ii = 0; curr != invalid_index; + curr = m_map.m_next_index[curr], ++ii) { + printf("%d[%d]: %d->%d\n", list, ii, m_map.key_at(curr), + m_map.value_at(curr)); } } }; @@ -280,19 +248,20 @@ template struct UnorderedMapCanAssign : public false_ {}; template -struct UnorderedMapCanAssign : public true_ {}; +struct UnorderedMapCanAssign : public true_ {}; template -struct UnorderedMapCanAssign : public true_ {}; +struct UnorderedMapCanAssign : public true_ {}; template -struct UnorderedMapCanAssign : public true_ {}; +struct UnorderedMapCanAssign + : public true_ {}; template -struct UnorderedMapCanAssign : public true_ {}; - - -}} //Kokkos::Impl +struct UnorderedMapCanAssign + : public true_ {}; -#endif // KOKKOS_UNORDERED_MAP_IMPL_HPP +} // namespace Impl +} // namespace Kokkos +#endif // KOKKOS_UNORDERED_MAP_IMPL_HPP diff --git a/lib/kokkos/containers/unit_tests/CMakeLists.txt b/lib/kokkos/containers/unit_tests/CMakeLists.txt index 8564bd9ddd..a83ab1293c 100644 --- a/lib/kokkos/containers/unit_tests/CMakeLists.txt +++ b/lib/kokkos/containers/unit_tests/CMakeLists.txt @@ -1,138 +1,35 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) - -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() -ENDIF() - -IF(Kokkos_ENABLE_Pthread) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_Threads - SOURCES - UnitTestMain.cpp - threads/TestThreads_BitSet.cpp - threads/TestThreads_DualView.cpp - threads/TestThreads_DynamicView.cpp - threads/TestThreads_DynRankViewAPI_generic.cpp - threads/TestThreads_DynRankViewAPI_rank12345.cpp - threads/TestThreads_DynRankViewAPI_rank67.cpp - threads/TestThreads_ErrorReporter.cpp - threads/TestThreads_OffsetView.cpp - threads/TestThreads_ScatterView.cpp - threads/TestThreads_StaticCrsGraph.cpp - threads/TestThreads_UnorderedMap.cpp - threads/TestThreads_Vector.cpp - threads/TestThreads_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_Serial) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_Serial - SOURCES - UnitTestMain.cpp - serial/TestSerial_BitSet.cpp - serial/TestSerial_DualView.cpp - serial/TestSerial_DynamicView.cpp - serial/TestSerial_DynRankViewAPI_generic.cpp - serial/TestSerial_DynRankViewAPI_rank12345.cpp - serial/TestSerial_DynRankViewAPI_rank67.cpp - serial/TestSerial_ErrorReporter.cpp - serial/TestSerial_OffsetView.cpp - serial/TestSerial_ScatterView.cpp - serial/TestSerial_StaticCrsGraph.cpp - serial/TestSerial_UnorderedMap.cpp - serial/TestSerial_Vector.cpp - serial/TestSerial_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_OpenMP) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_OpenMP - SOURCES - UnitTestMain.cpp - openmp/TestOpenMP_BitSet.cpp - openmp/TestOpenMP_DualView.cpp - openmp/TestOpenMP_DynamicView.cpp - openmp/TestOpenMP_DynRankViewAPI_generic.cpp - openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp - openmp/TestOpenMP_DynRankViewAPI_rank67.cpp - openmp/TestOpenMP_ErrorReporter.cpp - openmp/TestOpenMP_OffsetView.cpp - openmp/TestOpenMP_ScatterView.cpp - openmp/TestOpenMP_StaticCrsGraph.cpp - openmp/TestOpenMP_UnorderedMap.cpp - openmp/TestOpenMP_Vector.cpp - openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_HPX) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_HPX - SOURCES - UnitTestMain.cpp - hpx/TestHPX_BitSet.cpp - hpx/TestHPX_DualView.cpp - hpx/TestHPX_DynamicView.cpp - hpx/TestHPX_DynRankViewAPI_generic.cpp - hpx/TestHPX_DynRankViewAPI_rank12345.cpp - hpx/TestHPX_DynRankViewAPI_rank67.cpp - hpx/TestHPX_ErrorReporter.cpp - hpx/TestHPX_OffsetView.cpp - hpx/TestHPX_ScatterView.cpp - hpx/TestHPX_StaticCrsGraph.cpp - hpx/TestHPX_UnorderedMap.cpp - hpx/TestHPX_Vector.cpp - hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - -IF(Kokkos_ENABLE_Cuda) -TRIBITS_ADD_EXECUTABLE_AND_TEST( - UnitTest_Cuda - SOURCES - UnitTestMain.cpp - cuda/TestCuda_BitSet.cpp - cuda/TestCuda_DualView.cpp - cuda/TestCuda_DynamicView.cpp - cuda/TestCuda_DynRankViewAPI_generic.cpp - cuda/TestCuda_DynRankViewAPI_rank12345.cpp - cuda/TestCuda_DynRankViewAPI_rank67.cpp - cuda/TestCuda_ErrorReporter.cpp - cuda/TestCuda_OffsetView.cpp - cuda/TestCuda_ScatterView.cpp - cuda/TestCuda_StaticCrsGraph.cpp - cuda/TestCuda_UnorderedMap.cpp - cuda/TestCuda_Vector.cpp - cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp - COMM serial mpi - NUM_MPI_PROCS 1 - FAIL_REGULAR_EXPRESSION " FAILED " - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) -ENDIF() - +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src ) + +foreach(Tag Threads;Serial;OpenMP;HPX;Cuda) + # Because there is always an exception to the rule + if(Tag STREQUAL "Threads") + set(DEVICE "PTHREAD") + else() + string(TOUPPER ${Tag} DEVICE) + endif() + string(TOLOWER ${Tag} dir) + # Add test for that backend if it is enabled + if(Kokkos_ENABLE_${DEVICE}) + KOKKOS_ADD_EXECUTABLE_AND_TEST( + UnitTest_${Tag} + SOURCES + UnitTestMain.cpp + ${dir}/Test${Tag}_BitSet.cpp + ${dir}/Test${Tag}_DualView.cpp + ${dir}/Test${Tag}_DynamicView.cpp + ${dir}/Test${Tag}_DynRankViewAPI_generic.cpp + ${dir}/Test${Tag}_DynRankViewAPI_rank12345.cpp + ${dir}/Test${Tag}_DynRankViewAPI_rank67.cpp + ${dir}/Test${Tag}_ErrorReporter.cpp + ${dir}/Test${Tag}_OffsetView.cpp + ${dir}/Test${Tag}_ScatterView.cpp + ${dir}/Test${Tag}_StaticCrsGraph.cpp + ${dir}/Test${Tag}_UnorderedMap.cpp + ${dir}/Test${Tag}_Vector.cpp + ${dir}/Test${Tag}_ViewCtorPropEmbeddedDim.cpp + ) + endif() +endforeach() diff --git a/lib/kokkos/containers/unit_tests/TestBitset.hpp b/lib/kokkos/containers/unit_tests/TestBitset.hpp index 55d0e8b938..70528880a4 100644 --- a/lib/kokkos/containers/unit_tests/TestBitset.hpp +++ b/lib/kokkos/containers/unit_tests/TestBitset.hpp @@ -1,12 +1,13 @@ //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -35,7 +36,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER @@ -52,240 +53,208 @@ namespace Test { namespace Impl { template -struct TestBitset -{ +struct TestBitset { typedef Bitset bitset_type; typedef typename bitset_type::execution_space execution_space; typedef uint32_t value_type; bitset_type m_bitset; - TestBitset( bitset_type const& bitset) - : m_bitset(bitset) - {} + TestBitset(bitset_type const& bitset) : m_bitset(bitset) {} - unsigned testit(unsigned collisions) - { + unsigned testit(unsigned collisions) { execution_space().fence(); unsigned count = 0; - Kokkos::parallel_reduce( m_bitset.size()*collisions, *this, count); + Kokkos::parallel_reduce(m_bitset.size() * collisions, *this, count); return count; } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { dst += src; } + void join(volatile value_type& dst, const volatile value_type& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { + void operator()(uint32_t i, value_type& v) const { i = i % m_bitset.size(); if (Set) { if (m_bitset.set(i)) { if (m_bitset.test(i)) ++v; } - } - else { + } else { if (m_bitset.reset(i)) { if (!m_bitset.test(i)) ++v; } } } - }; template -struct TestBitsetTest -{ +struct TestBitsetTest { typedef Bitset bitset_type; typedef typename bitset_type::execution_space execution_space; typedef uint32_t value_type; bitset_type m_bitset; - TestBitsetTest( bitset_type const& bitset) - : m_bitset(bitset) - {} + TestBitsetTest(bitset_type const& bitset) : m_bitset(bitset) {} - unsigned testit() - { + unsigned testit() { execution_space().fence(); unsigned count = 0; - Kokkos::parallel_reduce( m_bitset.size(), *this, count); + Kokkos::parallel_reduce(m_bitset.size(), *this, count); return count; } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { dst += src; } + void join(volatile value_type& dst, const volatile value_type& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { - if (m_bitset.test( i )) ++v; + void operator()(uint32_t i, value_type& v) const { + if (m_bitset.test(i)) ++v; } }; template -struct TestBitsetAny -{ +struct TestBitsetAny { typedef Bitset bitset_type; typedef typename bitset_type::execution_space execution_space; typedef uint32_t value_type; bitset_type m_bitset; - TestBitsetAny( bitset_type const& bitset) - : m_bitset(bitset) - {} + TestBitsetAny(bitset_type const& bitset) : m_bitset(bitset) {} - unsigned testit() - { + unsigned testit() { execution_space().fence(); unsigned count = 0; - Kokkos::parallel_reduce( m_bitset.size(), *this, count); + Kokkos::parallel_reduce(m_bitset.size(), *this, count); return count; } - KOKKOS_INLINE_FUNCTION - void init( value_type & v ) const { v = 0; } + void init(value_type& v) const { v = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & dst, const volatile value_type & src ) const - { dst += src; } + void join(volatile value_type& dst, const volatile value_type& src) const { + dst += src; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & v) const - { - bool result = false; + void operator()(uint32_t i, value_type& v) const { + bool result = false; unsigned attempts = 0; - uint32_t hint = (i >> 4) << 4; + uint32_t hint = (i >> 4) << 4; while (attempts < m_bitset.max_hint()) { if (Set) { Kokkos::tie(result, hint) = m_bitset.find_any_unset_near(hint, i); if (result && m_bitset.set(hint)) { ++v; break; - } - else if (!result) { + } else if (!result) { ++attempts; } - } - else { + } else { Kokkos::tie(result, hint) = m_bitset.find_any_set_near(hint, i); if (result && m_bitset.reset(hint)) { ++v; break; - } - else if (!result) { + } else if (!result) { ++attempts; } } } } - }; -} // namespace Impl - - +} // namespace Impl template -void test_bitset() -{ - typedef Kokkos::Bitset< Device > bitset_type; - typedef Kokkos::ConstBitset< Device > const_bitset_type; +void test_bitset() { + typedef Kokkos::Bitset bitset_type; + typedef Kokkos::ConstBitset const_bitset_type; - //unsigned test_sizes[] = { 0u, 1000u, 1u<<14, 1u<<16, 10000001 }; - unsigned test_sizes[] = { 1000u, 1u<<14, 1u<<16, 10000001 }; + // unsigned test_sizes[] = { 0u, 1000u, 1u<<14, 1u<<16, 10000001 }; + unsigned test_sizes[] = {1000u, 1u << 14, 1u << 16, 10000001}; - for (int i=0, end = sizeof(test_sizes)/sizeof(unsigned); i f(bitset); + Impl::TestBitsetTest f(bitset); uint32_t count = f.testit(); EXPECT_EQ(0u, count); EXPECT_EQ(count, bitset.count()); } - //std::cout << " Check set() " << std::endl; + // std::cout << " Check set() " << std::endl; bitset.set(); // everything should be set { - Impl::TestBitsetTest< const_bitset_type > f(bitset); + Impl::TestBitsetTest f(bitset); uint32_t count = f.testit(); EXPECT_EQ(bitset.size(), count); EXPECT_EQ(count, bitset.count()); } - //std::cout << " Check reset() " << std::endl; + // std::cout << " Check reset() " << std::endl; bitset.reset(); EXPECT_EQ(0u, bitset.count()); - //std::cout << " Check set(i) " << std::endl; + // std::cout << " Check set(i) " << std::endl; // test setting bits { - Impl::TestBitset< bitset_type, true > f(bitset); + Impl::TestBitset f(bitset); uint32_t count = f.testit(10u); - EXPECT_EQ( bitset.size(), bitset.count()); - EXPECT_EQ( bitset.size(), count ); + EXPECT_EQ(bitset.size(), bitset.count()); + EXPECT_EQ(bitset.size(), count); } - //std::cout << " Check reset(i) " << std::endl; + // std::cout << " Check reset(i) " << std::endl; // test resetting bits { - Impl::TestBitset< bitset_type, false > f(bitset); + Impl::TestBitset f(bitset); uint32_t count = f.testit(10u); - EXPECT_EQ( bitset.size(), count); - EXPECT_EQ( 0u, bitset.count() ); + EXPECT_EQ(bitset.size(), count); + EXPECT_EQ(0u, bitset.count()); } - - //std::cout << " Check find_any_set(i) " << std::endl; + // std::cout << " Check find_any_set(i) " << std::endl; // test setting any bits { - Impl::TestBitsetAny< bitset_type, true > f(bitset); + Impl::TestBitsetAny f(bitset); uint32_t count = f.testit(); - EXPECT_EQ( bitset.size(), bitset.count()); - EXPECT_EQ( bitset.size(), count ); + EXPECT_EQ(bitset.size(), bitset.count()); + EXPECT_EQ(bitset.size(), count); } - //std::cout << " Check find_any_unset(i) " << std::endl; + // std::cout << " Check find_any_unset(i) " << std::endl; // test resetting any bits { - Impl::TestBitsetAny< bitset_type, false > f(bitset); + Impl::TestBitsetAny f(bitset); uint32_t count = f.testit(); - EXPECT_EQ( bitset.size(), count); - EXPECT_EQ( 0u, bitset.count() ); + EXPECT_EQ(bitset.size(), count); + EXPECT_EQ(0u, bitset.count()); } - } - -} - -TEST_F( TEST_CATEGORY, bitset ) -{ - test_bitset(); } -} // namespace Test +TEST(TEST_CATEGORY, bitset) { test_bitset(); } -#endif //KOKKOS_TEST_BITSET_HPP +} // namespace Test +#endif // KOKKOS_TEST_BITSET_HPP diff --git a/lib/kokkos/containers/unit_tests/TestDualView.hpp b/lib/kokkos/containers/unit_tests/TestDualView.hpp index 767f93c093..572ef48839 100644 --- a/lib/kokkos/containers/unit_tests/TestDualView.hpp +++ b/lib/kokkos/containers/unit_tests/TestDualView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,169 +56,159 @@ namespace Test { namespace Impl { - template - struct test_dualview_combinations - { - typedef test_dualview_combinations self_type; +template +struct test_dualview_combinations { + typedef test_dualview_combinations self_type; - typedef Scalar scalar_type; - typedef Device execution_space; + typedef Scalar scalar_type; + typedef Device execution_space; - Scalar reference; - Scalar result; + Scalar reference; + Scalar result; - template - Scalar run_me(unsigned int n,unsigned int m){ - if(n<10) n = 10; - if(m<3) m = 3; - ViewType a("A",n,m); + template + Scalar run_me(unsigned int n, unsigned int m) { + if (n < 10) n = 10; + if (m < 3) m = 3; + ViewType a("A", n, m); - Kokkos::deep_copy( a.d_view , 1 ); + Kokkos::deep_copy(a.d_view, 1); - a.template modify(); - a.template sync(); + a.template modify(); + a.template sync(); - a.h_view(5,1) = 3; - a.h_view(6,1) = 4; - a.h_view(7,2) = 5; - a.template modify(); - ViewType b = Kokkos::subview(a,std::pair(6,9),std::pair(0,1)); - a.template sync(); - b.template modify(); + a.h_view(5, 1) = 3; + a.h_view(6, 1) = 4; + a.h_view(7, 2) = 5; + a.template modify(); + ViewType b = Kokkos::subview(a, std::pair(6, 9), + std::pair(0, 1)); + a.template sync(); + b.template modify(); - Kokkos::deep_copy( b.d_view , 2 ); + Kokkos::deep_copy(b.d_view, 2); - a.template sync(); - Scalar count = 0; - for(unsigned int i = 0; i >(size,3); - } + a.template sync(); + Scalar count = 0; + for (unsigned int i = 0; i < a.d_view.extent(0); i++) + for (unsigned int j = 0; j < a.d_view.extent(1); j++) + count += a.h_view(i, j); + return count - a.d_view.extent(0) * a.d_view.extent(1) - 2 - 4 - 3 * 2; + } - }; + test_dualview_combinations(unsigned int size) { + result = run_me >( + size, 3); + } +}; - template < typename Scalar, class ViewType > - struct SumViewEntriesFunctor { +template +struct SumViewEntriesFunctor { + typedef Scalar value_type; - typedef Scalar value_type; + ViewType fv; - ViewType fv; + SumViewEntriesFunctor(const ViewType& fv_) : fv(fv_) {} - SumViewEntriesFunctor ( const ViewType & fv_ ) : fv(fv_) {} - - KOKKOS_INLINE_FUNCTION - void operator() ( const int i , value_type & total ) const { - for ( size_t j = 0; j < fv.extent(1); ++j ) { - total += fv(i,j); - } + KOKKOS_INLINE_FUNCTION + void operator()(const int i, value_type& total) const { + for (size_t j = 0; j < fv.extent(1); ++j) { + total += fv(i, j); } + } +}; + +template +struct test_dual_view_deep_copy { + typedef Scalar scalar_type; + typedef Device execution_space; + + template + void run_me() { + const unsigned int n = 10; + const unsigned int m = 5; + const unsigned int sum_total = n * m; + + ViewType a("A", n, m); + ViewType b("B", n, m); + + Kokkos::deep_copy(a.d_view, 1); + + a.template modify(); + a.template sync(); + + // Check device view is initialized as expected + scalar_type a_d_sum = 0; + // Execute on the execution_space associated with t_dev's memory space + typedef typename ViewType::t_dev::memory_space::execution_space + t_dev_exec_space; + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, n), + SumViewEntriesFunctor(a.d_view), + a_d_sum); + ASSERT_EQ(a_d_sum, sum_total); + + // Check host view is synced as expected + scalar_type a_h_sum = 0; + for (size_t i = 0; i < a.h_view.extent(0); ++i) + for (size_t j = 0; j < a.h_view.extent(1); ++j) { + a_h_sum += a.h_view(i, j); + } - }; - - - template - struct test_dual_view_deep_copy - { - typedef Scalar scalar_type; - typedef Device execution_space; - - template - void run_me() { - - const unsigned int n = 10; - const unsigned int m = 5; - const unsigned int sum_total = n * m; - - ViewType a("A",n,m); - ViewType b("B",n,m); - - Kokkos::deep_copy( a.d_view , 1 ); - - a.template modify(); - a.template sync(); - - // Check device view is initialized as expected - scalar_type a_d_sum = 0; - // Execute on the execution_space associated with t_dev's memory space - typedef typename ViewType::t_dev::memory_space::execution_space t_dev_exec_space; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0,n), SumViewEntriesFunctor(a.d_view), a_d_sum ); - ASSERT_EQ(a_d_sum, sum_total); - - // Check host view is synced as expected - scalar_type a_h_sum = 0; - for ( size_t i = 0; i < a.h_view.extent(0); ++i ) - for ( size_t j = 0; j < a.h_view.extent(1); ++j ) { - a_h_sum += a.h_view(i,j); - } - - ASSERT_EQ(a_h_sum, sum_total); - - - // Test deep_copy - Kokkos::deep_copy( b, a ); - b.template sync(); - - // Perform same checks on b as done on a - // Check device view is initialized as expected - scalar_type b_d_sum = 0; - // Execute on the execution_space associated with t_dev's memory space - Kokkos::parallel_reduce( Kokkos::RangePolicy(0,n), SumViewEntriesFunctor(b.d_view), b_d_sum ); - ASSERT_EQ(b_d_sum, sum_total); - - // Check host view is synced as expected - scalar_type b_h_sum = 0; - for ( size_t i = 0; i < b.h_view.extent(0); ++i ) - for ( size_t j = 0; j < b.h_view.extent(1); ++j ) { - b_h_sum += b.h_view(i,j); - } - - ASSERT_EQ(b_h_sum, sum_total); - - } // end run_me - - test_dual_view_deep_copy() - { - run_me< Kokkos::DualView >(); - } + ASSERT_EQ(a_h_sum, sum_total); + + // Test deep_copy + Kokkos::deep_copy(b, a); + b.template sync(); + + // Perform same checks on b as done on a + // Check device view is initialized as expected + scalar_type b_d_sum = 0; + // Execute on the execution_space associated with t_dev's memory space + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, n), + SumViewEntriesFunctor(b.d_view), + b_d_sum); + ASSERT_EQ(b_d_sum, sum_total); + + // Check host view is synced as expected + scalar_type b_h_sum = 0; + for (size_t i = 0; i < b.h_view.extent(0); ++i) + for (size_t j = 0; j < b.h_view.extent(1); ++j) { + b_h_sum += b.h_view(i, j); + } - }; + ASSERT_EQ(b_h_sum, sum_total); -} // namespace Impl + } // end run_me + test_dual_view_deep_copy() { + run_me >(); + } +}; +} // namespace Impl template -void test_dualview_combinations(unsigned int size) -{ - Impl::test_dualview_combinations test(size); - ASSERT_EQ( test.result,0); - +void test_dualview_combinations(unsigned int size) { + Impl::test_dualview_combinations test(size); + ASSERT_EQ(test.result, 0); } template -void test_dualview_deep_copy() -{ - Impl::test_dual_view_deep_copy (); +void test_dualview_deep_copy() { + Impl::test_dual_view_deep_copy(); } -TEST_F( TEST_CATEGORY, dualview_combination) { - test_dualview_combinations(10); +TEST(TEST_CATEGORY, dualview_combination) { + test_dualview_combinations(10); } -TEST_F( TEST_CATEGORY, dualview_deep_copy) { - test_dualview_deep_copy(); - test_dualview_deep_copy(); +TEST(TEST_CATEGORY, dualview_deep_copy) { + test_dualview_deep_copy(); + test_dualview_deep_copy(); } +} // namespace Test -} // namespace Test - -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP - +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp index 13e56c9f8d..3692aa8a12 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -51,680 +52,661 @@ /*--------------------------------------------------------------------------*/ - /*--------------------------------------------------------------------------*/ namespace Test { -template< class T , class ... P > -size_t allocation_count( const Kokkos::DynRankView & view ) -{ +template +size_t allocation_count(const Kokkos::DynRankView& view) { const size_t card = view.size(); const size_t alloc = view.span(); - return card <= alloc ? alloc : 0 ; + return card <= alloc ? alloc : 0; } /*--------------------------------------------------------------------------*/ -template< typename T, class DeviceType> -struct TestViewOperator -{ - typedef DeviceType execution_space ; +template +struct TestViewOperator { + typedef DeviceType execution_space; - static const unsigned N = 100 ; - static const unsigned D = 3 ; + static const unsigned N = 100; + static const unsigned D = 3; - typedef Kokkos::DynRankView< T , execution_space > view_type ; + typedef Kokkos::DynRankView view_type; - const view_type v1 ; - const view_type v2 ; + const view_type v1; + const view_type v2; - TestViewOperator() - : v1( "v1" , N , D ) - , v2( "v2" , N , D ) - {} + TestViewOperator() : v1("v1", N, D), v2("v2", N, D) {} - static void testit() - { - Kokkos::parallel_for( N , TestViewOperator() ); - } + static void testit() { Kokkos::parallel_for(N, TestViewOperator()); } KOKKOS_INLINE_FUNCTION - void operator()( const unsigned i ) const - { - const unsigned X = 0 ; - const unsigned Y = 1 ; - const unsigned Z = 2 ; - - v2(i,X) = v1(i,X); - v2(i,Y) = v1(i,Y); - v2(i,Z) = v1(i,Z); + void operator()(const unsigned i) const { + const unsigned X = 0; + const unsigned Y = 1; + const unsigned Z = 2; + + v2(i, X) = v1(i, X); + v2(i, Y) = v1(i, Y); + v2(i, Z) = v1(i, Z); } }; /*--------------------------------------------------------------------------*/ -template< class DataType , - class DeviceType , - unsigned Rank > -struct TestViewOperator_LeftAndRight ; +template +struct TestViewOperator_LeftAndRight; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 7 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3, unsigned N4, unsigned N5, + unsigned N6) + : left("left", N0, N1, N2, N3, N4, N5, N6), + right("right", N0, N1, N2, N3, N4, N5, N6), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5, unsigned N6 ) - : left( "left" , N0, N1, N2, N3, N4, N5, N6 ) - , right( "right" , N0, N1, N2, N3, N4, N5, N6 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, + unsigned N4, unsigned N5, unsigned N6) { + TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4, N5, N6); - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5, unsigned N6 ) - { - TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4, N5, N6 ); + int error_flag = 0; - int error_flag = 0 ; + Kokkos::parallel_reduce(1, driver, error_flag); - Kokkos::parallel_reduce( 1 , driver , error_flag ); - - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i6 = 0 ; i6 < unsigned(left.extent(6)) ; ++i6 ) - for ( unsigned i5 = 0 ; i5 < unsigned(left.extent(5)) ; ++i5 ) - for ( unsigned i4 = 0 ; i4 < unsigned(left.extent(4)) ; ++i4 ) - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3, i4, i5, i6 ) - - & left( 0, 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - for ( unsigned i4 = 0 ; i4 < unsigned(right.extent(4)) ; ++i4 ) - for ( unsigned i5 = 0 ; i5 < unsigned(right.extent(5)) ; ++i5 ) - for ( unsigned i6 = 0 ; i6 < unsigned(right.extent(6)) ; ++i6 ) - { - const long j = & right( i0, i1, i2, i3, i4, i5, i6 ) - - & right( 0, 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i6 = 0; i6 < unsigned(left.extent(6)); ++i6) + for (unsigned i5 = 0; i5 < unsigned(left.extent(5)); ++i5) + for (unsigned i4 = 0; i4 < unsigned(left.extent(4)); ++i4) + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2, i3, i4, i5, i6) - + &left(0, 0, 0, 0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) + for (unsigned i4 = 0; i4 < unsigned(right.extent(4)); ++i4) + for (unsigned i5 = 0; i5 < unsigned(right.extent(5)); ++i5) + for (unsigned i6 = 0; i6 < unsigned(right.extent(6)); ++i6) { + const long j = &right(i0, i1, i2, i3, i4, i5, i6) - + &right(0, 0, 0, 0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 6 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3, unsigned N4, unsigned N5) + : left("left", N0, N1, N2, N3, N4, N5), + right("right", N0, N1, N2, N3, N4, N5), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5 ) - : left( "left" , N0, N1, N2, N3, N4, N5 ) - , right( "right" , N0, N1, N2, N3, N4, N5 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, + unsigned N4, unsigned N5) { + TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4, N5); - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4, unsigned N5) - { - TestViewOperator_LeftAndRight driver (N0, N1, N2, N3, N4, N5); + int error_flag = 0; - int error_flag = 0 ; + Kokkos::parallel_reduce(1, driver, error_flag); - Kokkos::parallel_reduce( 1 , driver , error_flag ); - - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i5 = 0 ; i5 < unsigned(left.extent(5)) ; ++i5 ) - for ( unsigned i4 = 0 ; i4 < unsigned(left.extent(4)) ; ++i4 ) - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3, i4, i5 ) - - & left( 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - for ( unsigned i4 = 0 ; i4 < unsigned(right.extent(4)) ; ++i4 ) - for ( unsigned i5 = 0 ; i5 < unsigned(right.extent(5)) ; ++i5 ) - { - const long j = & right( i0, i1, i2, i3, i4, i5 ) - - & right( 0, 0, 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i5 = 0; i5 < unsigned(left.extent(5)); ++i5) + for (unsigned i4 = 0; i4 < unsigned(left.extent(4)); ++i4) + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = + &left(i0, i1, i2, i3, i4, i5) - &left(0, 0, 0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) + for (unsigned i4 = 0; i4 < unsigned(right.extent(4)); ++i4) + for (unsigned i5 = 0; i5 < unsigned(right.extent(5)); ++i5) { + const long j = + &right(i0, i1, i2, i3, i4, i5) - &right(0, 0, 0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 5 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } - - - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; - - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; - - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutStride, execution_space > stride_view ; - - left_view left ; - right_view right ; - stride_view left_stride ; - stride_view right_stride ; - long left_alloc ; - long right_alloc ; - - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4 ) - : left( "left" , N0, N1, N2, N3, N4 ) - , right( "right" , N0, N1, N2, N3, N4 ) - , left_stride( left ) - , right_stride( right ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} - - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, unsigned N4) - { + static void init(value_type& update) { update = 0; } + + typedef Kokkos::DynRankView + left_view; + + typedef Kokkos::DynRankView + right_view; + + typedef Kokkos::DynRankView + stride_view; + + left_view left; + right_view right; + stride_view left_stride; + stride_view right_stride; + long left_alloc; + long right_alloc; + + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3, unsigned N4) + : left("left", N0, N1, N2, N3, N4), + right("right", N0, N1, N2, N3, N4), + left_stride(left), + right_stride(right), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} + + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3, + unsigned N4) { TestViewOperator_LeftAndRight driver(N0, N1, N2, N3, N4); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i4 = 0 ; i4 < unsigned(left.extent(4)) ; ++i4 ) - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3, i4 ) - - & left( 0, 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - - if ( & left( i0, i1, i2, i3, i4 ) != - & left_stride( i0, i1, i2, i3, i4 ) ) { update |= 4 ; } - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - for ( unsigned i4 = 0 ; i4 < unsigned(right.extent(4)) ; ++i4 ) - { - const long j = & right( i0, i1, i2, i3, i4 ) - - & right( 0, 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - - if ( & right( i0, i1, i2, i3, i4 ) != - & right_stride( i0, i1, i2, i3, i4 ) ) { update |= 8 ; } - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i4 = 0; i4 < unsigned(left.extent(4)); ++i4) + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2, i3, i4) - &left(0, 0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + + if (&left(i0, i1, i2, i3, i4) != + &left_stride(i0, i1, i2, i3, i4)) { + update |= 4; + } + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) + for (unsigned i4 = 0; i4 < unsigned(right.extent(4)); ++i4) { + const long j = &right(i0, i1, i2, i3, i4) - &right(0, 0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + + if (&right(i0, i1, i2, i3, i4) != + &right_stride(i0, i1, i2, i3, i4)) { + update |= 8; + } + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 4 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } - + static void init(value_type& update) { update = 0; } - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + typedef Kokkos::DynRankView + right_view; - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; - TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, unsigned N3) - : left( "left" , N0, N1, N2, N3 ) - , right( "right" , N0, N1, N2, N3 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2, + unsigned N3) + : left("left", N0, N1, N2, N3), + right("right", N0, N1, N2, N3), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3) - { - TestViewOperator_LeftAndRight driver (N0, N1, N2, N3); + static void testit(unsigned N0, unsigned N1, unsigned N2, unsigned N3) { + TestViewOperator_LeftAndRight driver(N0, N1, N2, N3); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i3 = 0 ; i3 < unsigned(left.extent(3)) ; ++i3 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2, i3 ) - - & left( 0, 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - for ( unsigned i3 = 0 ; i3 < unsigned(right.extent(3)) ; ++i3 ) - { - const long j = & right( i0, i1, i2, i3 ) - - & right( 0, 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i3 = 0; i3 < unsigned(left.extent(3)); ++i3) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2, i3) - &left(0, 0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) + for (unsigned i3 = 0; i3 < unsigned(right.extent(3)); ++i3) { + const long j = &right(i0, i1, i2, i3) - &right(0, 0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 3 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } - + static void init(value_type& update) { update = 0; } - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutStride, execution_space > stride_view ; + typedef Kokkos::DynRankView + stride_view; - left_view left ; - right_view right ; - stride_view left_stride ; - stride_view right_stride ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + stride_view left_stride; + stride_view right_stride; + long left_alloc; + long right_alloc; TestViewOperator_LeftAndRight(unsigned N0, unsigned N1, unsigned N2) - : left( std::string("left") , N0, N1, N2 ) - , right( std::string("right") , N0, N1, N2 ) - , left_stride( left ) - , right_stride( right ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + : left(std::string("left"), N0, N1, N2), + right(std::string("right"), N0, N1, N2), + left_stride(left), + right_stride(right), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - static void testit(unsigned N0, unsigned N1, unsigned N2) - { - TestViewOperator_LeftAndRight driver (N0, N1, N2); + static void testit(unsigned N0, unsigned N1, unsigned N2) { + TestViewOperator_LeftAndRight driver(N0, N1, N2); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1, i2 ) - - & left( 0, 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - - if ( & left(i0,i1,i2) != & left_stride(i0,i1,i2) ) { update |= 4 ; } - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(right.extent(2)) ; ++i2 ) - { - const long j = & right( i0, i1, i2 ) - - & right( 0, 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - - if ( & right(i0,i1,i2) != & right_stride(i0,i1,i2) ) { update |= 8 ; } - } - - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i2 = 0 ; i2 < unsigned(left.extent(2)) ; ++i2 ) - { - if ( & left(i0,i1,i2) != & left(i0,i1,i2,0,0,0,0) ) { update |= 3 ; } - if ( & right(i0,i1,i2) != & right(i0,i1,i2,0,0,0,0) ) { update |= 3 ; } - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1, i2) - &left(0, 0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + + if (&left(i0, i1, i2) != &left_stride(i0, i1, i2)) { + update |= 4; + } + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(right.extent(2)); ++i2) { + const long j = &right(i0, i1, i2) - &right(0, 0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + + if (&right(i0, i1, i2) != &right_stride(i0, i1, i2)) { + update |= 8; + } + } + + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i2 = 0; i2 < unsigned(left.extent(2)); ++i2) { + if (&left(i0, i1, i2) != &left(i0, i1, i2, 0, 0, 0, 0)) { + update |= 3; + } + if (&right(i0, i1, i2) != &right(i0, i1, i2, 0, 0, 0, 0)) { + update |= 3; + } + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 2 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; - - left_view left ; - right_view right ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + long left_alloc; + long right_alloc; TestViewOperator_LeftAndRight(unsigned N0, unsigned N1) - : left( "left" , N0, N1 ) - , right( "right" , N0, N1 ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} - - static void testit(unsigned N0, unsigned N1) - { + : left("left", N0, N1), + right("right", N0, N1), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} + + static void testit(unsigned N0, unsigned N1) { TestViewOperator_LeftAndRight driver(N0, N1); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - long offset ; - - offset = -1 ; - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - const long j = & left( i0, i1 ) - - & left( 0, 0 ); - if ( j <= offset || left_alloc <= j ) { update |= 1 ; } - offset = j ; - } - - offset = -1 ; - for ( unsigned i0 = 0 ; i0 < unsigned(right.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(right.extent(1)) ; ++i1 ) - { - const long j = & right( i0, i1 ) - - & right( 0, 0 ); - if ( j <= offset || right_alloc <= j ) { update |= 2 ; } - offset = j ; - } - - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - for ( unsigned i1 = 0 ; i1 < unsigned(left.extent(1)) ; ++i1 ) - { - if ( & left(i0,i1) != & left(i0,i1,0,0,0,0,0) ) { update |= 3 ; } - if ( & right(i0,i1) != & right(i0,i1,0,0,0,0,0) ) { update |= 3 ; } - } + void operator()(const size_type, value_type& update) const { + long offset; + + offset = -1; + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + const long j = &left(i0, i1) - &left(0, 0); + if (j <= offset || left_alloc <= j) { + update |= 1; + } + offset = j; + } + + offset = -1; + for (unsigned i0 = 0; i0 < unsigned(right.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(right.extent(1)); ++i1) { + const long j = &right(i0, i1) - &right(0, 0); + if (j <= offset || right_alloc <= j) { + update |= 2; + } + offset = j; + } + + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) + for (unsigned i1 = 0; i1 < unsigned(left.extent(1)); ++i1) { + if (&left(i0, i1) != &left(i0, i1, 0, 0, 0, 0, 0)) { + update |= 3; + } + if (&right(i0, i1) != &right(i0, i1, 0, 0, 0, 0, 0)) { + update |= 3; + } + } } }; -template< class DataType , class DeviceType > -struct TestViewOperator_LeftAndRight< DataType , DeviceType , 1 > -{ - typedef DeviceType execution_space ; - typedef typename execution_space::memory_space memory_space ; - typedef typename execution_space::size_type size_type ; +template +struct TestViewOperator_LeftAndRight { + typedef DeviceType execution_space; + typedef typename execution_space::memory_space memory_space; + typedef typename execution_space::size_type size_type; - typedef int value_type ; + typedef int value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & input ) - { update |= input ; } + static void join(volatile value_type& update, + const volatile value_type& input) { + update |= input; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } + typedef Kokkos::DynRankView + left_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutLeft, execution_space > left_view ; + typedef Kokkos::DynRankView + right_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutRight, execution_space > right_view ; + typedef Kokkos::DynRankView + stride_view; - typedef Kokkos:: - DynRankView< DataType, Kokkos::LayoutStride, execution_space > stride_view ; - - left_view left ; - right_view right ; - stride_view left_stride ; - stride_view right_stride ; - long left_alloc ; - long right_alloc ; + left_view left; + right_view right; + stride_view left_stride; + stride_view right_stride; + long left_alloc; + long right_alloc; TestViewOperator_LeftAndRight(unsigned N0) - : left( "left" , N0 ) - , right( "right" , N0 ) - , left_stride( left ) - , right_stride( right ) - , left_alloc( allocation_count( left ) ) - , right_alloc( allocation_count( right ) ) - {} + : left("left", N0), + right("right", N0), + left_stride(left), + right_stride(right), + left_alloc(allocation_count(left)), + right_alloc(allocation_count(right)) {} - static void testit(unsigned N0) - { - TestViewOperator_LeftAndRight driver (N0) ; + static void testit(unsigned N0) { + TestViewOperator_LeftAndRight driver(N0); - int error_flag = 0 ; + int error_flag = 0; - Kokkos::parallel_reduce( 1 , driver , error_flag ); + Kokkos::parallel_reduce(1, driver, error_flag); - ASSERT_EQ( error_flag , 0 ); + ASSERT_EQ(error_flag, 0); } KOKKOS_INLINE_FUNCTION - void operator()( const size_type , value_type & update ) const - { - for ( unsigned i0 = 0 ; i0 < unsigned(left.extent(0)) ; ++i0 ) - { - if ( & left(i0) != & left(i0,0,0,0,0,0,0) ) { update |= 3 ; } - if ( & right(i0) != & right(i0,0,0,0,0,0,0) ) { update |= 3 ; } - if ( & left(i0) != & left_stride(i0) ) { update |= 4 ; } - if ( & right(i0) != & right_stride(i0) ) { update |= 8 ; } + void operator()(const size_type, value_type& update) const { + for (unsigned i0 = 0; i0 < unsigned(left.extent(0)); ++i0) { + if (&left(i0) != &left(i0, 0, 0, 0, 0, 0, 0)) { + update |= 3; + } + if (&right(i0) != &right(i0, 0, 0, 0, 0, 0, 0)) { + update |= 3; + } + if (&left(i0) != &left_stride(i0)) { + update |= 4; + } + if (&right(i0) != &right_stride(i0)) { + update |= 8; + } } } }; /*--------------------------------------------------------------------------*/ -template< typename T, class DeviceType > -class TestDynViewAPI -{ -public: - typedef DeviceType device ; +template +class TestDynViewAPI { + public: + typedef DeviceType device; - enum { N0 = 1000 , - N1 = 3 , - N2 = 5 , - N3 = 7 }; + enum { N0 = 1000, N1 = 3, N2 = 5, N3 = 7 }; - typedef Kokkos::DynRankView< T , device > dView0 ; - typedef Kokkos::DynRankView< const T , device > const_dView0 ; + typedef Kokkos::DynRankView dView0; + typedef Kokkos::DynRankView const_dView0; - typedef Kokkos::DynRankView< T, device, Kokkos::MemoryUnmanaged > dView0_unmanaged ; - typedef typename dView0::host_mirror_space host_drv_space ; + typedef Kokkos::DynRankView + dView0_unmanaged; + typedef typename dView0::host_mirror_space host_drv_space; - typedef Kokkos::View< T , device > View0 ; - typedef Kokkos::View< T* , device > View1 ; - typedef Kokkos::View< T******* , device > View7 ; + typedef Kokkos::View View0; + typedef Kokkos::View View1; + typedef Kokkos::View View7; - typedef typename View0::host_mirror_space host_view_space ; + typedef typename View0::host_mirror_space host_view_space; - TestDynViewAPI() - { - } + TestDynViewAPI() {} static void run_tests() { run_test_resize_realloc(); @@ -738,459 +720,475 @@ public: run_test_vector(); } - static void run_operator_test_rank12345 () { - TestViewOperator< T , device >::testit(); - TestViewOperator_LeftAndRight< int , device , 5 >::testit(2,3,4,2,3); - TestViewOperator_LeftAndRight< int , device , 4 >::testit(2,3,4,2); - TestViewOperator_LeftAndRight< int , device , 3 >::testit(2,3,4); - TestViewOperator_LeftAndRight< int , device , 2 >::testit(2,3); - TestViewOperator_LeftAndRight< int , device , 1 >::testit(2); + static void run_operator_test_rank12345() { + TestViewOperator::testit(); + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2, 3); + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2); + TestViewOperator_LeftAndRight::testit(2, 3, 4); + TestViewOperator_LeftAndRight::testit(2, 3); + TestViewOperator_LeftAndRight::testit(2); } - static void run_operator_test_rank67 () { - TestViewOperator_LeftAndRight< int , device , 7 >::testit(2,3,4,2,3,4,2); - TestViewOperator_LeftAndRight< int , device , 6 >::testit(2,3,4,2,3,4); + static void run_operator_test_rank67() { + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2, 3, 4, 2); + TestViewOperator_LeftAndRight::testit(2, 3, 4, 2, 3, 4); } - static void run_test_resize_realloc() - { + static void run_test_resize_realloc() { dView0 drv0("drv0", 10, 20, 30); - ASSERT_EQ( drv0.rank(), 3); + ASSERT_EQ(drv0.rank(), 3); Kokkos::resize(drv0, 5, 10); - ASSERT_EQ( drv0.rank(), 2); - ASSERT_EQ( drv0.extent(0), 5); - ASSERT_EQ( drv0.extent(1), 10); - ASSERT_EQ( drv0.extent(2), 1); + ASSERT_EQ(drv0.rank(), 2); + ASSERT_EQ(drv0.extent(0), 5); + ASSERT_EQ(drv0.extent(1), 10); + ASSERT_EQ(drv0.extent(2), 1); Kokkos::realloc(drv0, 10, 20); - ASSERT_EQ( drv0.rank(), 2); - ASSERT_EQ( drv0.extent(0), 10); - ASSERT_EQ( drv0.extent(1), 20); - ASSERT_EQ( drv0.extent(2), 1); - + ASSERT_EQ(drv0.rank(), 2); + ASSERT_EQ(drv0.extent(0), 10); + ASSERT_EQ(drv0.extent(1), 20); + ASSERT_EQ(drv0.extent(2), 1); } - static void run_test_mirror() - { - typedef Kokkos::DynRankView< int , host_drv_space > view_type ; - typedef typename view_type::HostMirror mirror_type ; + static void run_test_mirror() { + typedef Kokkos::DynRankView view_type; + typedef typename view_type::HostMirror mirror_type; view_type a("a"); mirror_type am = Kokkos::create_mirror_view(a); mirror_type ax = Kokkos::create_mirror(a); - ASSERT_EQ( & a() , & am() ); - ASSERT_EQ( a.rank() , am.rank() ); - ASSERT_EQ( ax.rank() , am.rank() ); + ASSERT_EQ(&a(), &am()); + ASSERT_EQ(a.rank(), am.rank()); + ASSERT_EQ(ax.rank(), am.rank()); { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = (a_h.data() ==a_h2.data())?1:0; - int equal_ptr_h_d = (a_h.data() ==a_d. data())?1:0; - int equal_ptr_h2_d = (a_h2.data()==a_d. data())?1:0; - - ASSERT_EQ(equal_ptr_h_h2,0); - ASSERT_EQ(equal_ptr_h_d ,0); - ASSERT_EQ(equal_ptr_h2_d,0); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); - - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); - } - { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = (a_h.data() ==a_h2.data())?1:0; - int equal_ptr_h_d = (a_h.data() ==a_d. data())?1:0; - int equal_ptr_h2_d = (a_h2.data()==a_d. data())?1:0; - - ASSERT_EQ(equal_ptr_h_h2,0); - ASSERT_EQ(equal_ptr_h_d ,0); - ASSERT_EQ(equal_ptr_h2_d,0); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); - - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); - } + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror(typename device::memory_space(), a_h); - { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror_view(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = a_h.data() ==a_h2.data()?1:0; - int equal_ptr_h_d = a_h.data() ==a_d. data()?1:0; - int equal_ptr_h2_d = a_h2.data()==a_d. data()?1:0; + int equal_ptr_h_h2 = (a_h.data() == a_h2.data()) ? 1 : 0; + int equal_ptr_h_d = (a_h.data() == a_d.data()) ? 1 : 0; + int equal_ptr_h2_d = (a_h2.data() == a_d.data()) ? 1 : 0; - int is_same_memspace = std::is_same::value?1:0; - ASSERT_EQ(equal_ptr_h_h2,1); - ASSERT_EQ(equal_ptr_h_d ,is_same_memspace); - ASSERT_EQ(equal_ptr_h2_d ,is_same_memspace); + ASSERT_EQ(equal_ptr_h_h2, 0); + ASSERT_EQ(equal_ptr_h_d, 0); + ASSERT_EQ(equal_ptr_h2_d, 0); - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); } { - Kokkos::DynRankView a_h("A",1000); - auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror_view(typename device::memory_space(),a_h); + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror(typename device::memory_space(), a_h); - int equal_ptr_h_h2 = a_h.data() ==a_h2.data()?1:0; - int equal_ptr_h_d = a_h.data() ==a_d. data()?1:0; - int equal_ptr_h2_d = a_h2.data()==a_d. data()?1:0; + int equal_ptr_h_h2 = (a_h.data() == a_h2.data()) ? 1 : 0; + int equal_ptr_h_d = (a_h.data() == a_d.data()) ? 1 : 0; + int equal_ptr_h2_d = (a_h2.data() == a_d.data()) ? 1 : 0; - int is_same_memspace = std::is_same::value?1:0; - ASSERT_EQ(equal_ptr_h_h2,1); - ASSERT_EQ(equal_ptr_h_d ,is_same_memspace); - ASSERT_EQ(equal_ptr_h2_d ,is_same_memspace); + ASSERT_EQ(equal_ptr_h_h2, 0); + ASSERT_EQ(equal_ptr_h_d, 0); + ASSERT_EQ(equal_ptr_h2_d, 0); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); } + { - typedef Kokkos::DynRankView< int , Kokkos::LayoutStride , Kokkos::HostSpace > view_stride_type ; - unsigned order[] = { 6,5,4,3,2,1,0 }, dimen[] = { N0, N1, N2, 2, 2, 2, 2 }; //LayoutRight equivalent - view_stride_type a_h( "a" , Kokkos::LayoutStride::order_dimensions(7, order, dimen) ); - auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(),a_h); - auto a_d = Kokkos::create_mirror_view(typename device::memory_space(),a_h); - - int equal_ptr_h_h2 = a_h.data() ==a_h2.data()?1:0; - int equal_ptr_h_d = a_h.data() ==a_d. data()?1:0; - int equal_ptr_h2_d = a_h2.data()==a_d. data()?1:0; - - int is_same_memspace = std::is_same::value?1:0; - ASSERT_EQ(equal_ptr_h_h2,1); - ASSERT_EQ(equal_ptr_h_d ,is_same_memspace); - ASSERT_EQ(equal_ptr_h2_d ,is_same_memspace); - - ASSERT_EQ(a_h.extent(0),a_h2.extent(0)); - ASSERT_EQ(a_h.extent(0),a_d .extent(0)); - - ASSERT_EQ(a_h.rank(),a_h2.rank()); - ASSERT_EQ(a_h.rank(),a_d.rank()); + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(), a_h); + auto a_d = + Kokkos::create_mirror_view(typename device::memory_space(), a_h); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + } + { + Kokkos::DynRankView a_h( + "A", 1000); + auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(), a_h); + auto a_d = + Kokkos::create_mirror_view(typename device::memory_space(), a_h); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + } + { + typedef Kokkos::DynRankView + view_stride_type; + unsigned order[] = {6, 5, 4, 3, 2, 1, 0}, + dimen[] = {N0, N1, N2, 2, 2, 2, 2}; // LayoutRight equivalent + view_stride_type a_h( + "a", Kokkos::LayoutStride::order_dimensions(7, order, dimen)); + auto a_h2 = Kokkos::create_mirror_view(Kokkos::HostSpace(), a_h); + auto a_d = + Kokkos::create_mirror_view(typename device::memory_space(), a_h); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); } } - static void run_test_mirror_and_copy() - { + static void run_test_mirror_and_copy() { // LayoutLeft { - Kokkos::DynRankView< double, Kokkos::LayoutLeft, Kokkos::HostSpace > a_org( "A", 10 ); + Kokkos::DynRankView a_org( + "A", 10); a_org(5) = 42.0; - Kokkos::DynRankView< double, Kokkos::LayoutLeft, Kokkos::HostSpace > a_h = a_org; - auto a_h2 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_h ); - auto a_d = Kokkos::create_mirror_view_and_copy( DeviceType(), a_h ); - auto a_h3 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_d ); - - int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; - int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; - int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; - int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; - - int is_same_memspace = std::is_same< Kokkos::HostSpace, typename DeviceType::memory_space >::value ? 1 : 0; - ASSERT_EQ( equal_ptr_h_h2, 1 ); - ASSERT_EQ( equal_ptr_h_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h2_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h3_d, is_same_memspace ); - - ASSERT_EQ( a_h.extent(0), a_h3.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_h2.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_d .extent(0) ); - ASSERT_EQ( a_h.extent(0), a_h3.extent(0) ); - ASSERT_EQ( a_h.rank(), a_org.rank() ); - ASSERT_EQ( a_h.rank(), a_h2.rank() ); - ASSERT_EQ( a_h.rank(), a_h3.rank() ); - ASSERT_EQ( a_h.rank(), a_d.rank() ); - ASSERT_EQ( a_org(5), a_h3(5) ); + Kokkos::DynRankView a_h = + a_org; + auto a_h2 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror_view_and_copy(DeviceType(), a_h); + auto a_h3 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_d); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h3_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h3.extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + ASSERT_EQ(a_h.extent(0), a_h3.extent(0)); + ASSERT_EQ(a_h.rank(), a_org.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_h3.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + ASSERT_EQ(a_org(5), a_h3(5)); } // LayoutRight { - Kokkos::DynRankView< double, Kokkos::LayoutRight, Kokkos::HostSpace > a_org( "A", 10 ); + Kokkos::DynRankView a_org( + "A", 10); a_org(5) = 42.0; - Kokkos::DynRankView< double, Kokkos::LayoutRight, Kokkos::HostSpace > a_h = a_org; - auto a_h2 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_h ); - auto a_d = Kokkos::create_mirror_view_and_copy( DeviceType(), a_h ); - auto a_h3 = Kokkos::create_mirror_view_and_copy( Kokkos::HostSpace(), a_d ); - - int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; - int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; - int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; - int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; - - int is_same_memspace = std::is_same< Kokkos::HostSpace, typename DeviceType::memory_space >::value ? 1 : 0; - ASSERT_EQ( equal_ptr_h_h2, 1 ); - ASSERT_EQ( equal_ptr_h_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h2_d, is_same_memspace ); - ASSERT_EQ( equal_ptr_h3_d, is_same_memspace ); - - ASSERT_EQ( a_h.extent(0), a_h3.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_h2.extent(0) ); - ASSERT_EQ( a_h.extent(0), a_d .extent(0) ); - ASSERT_EQ( a_h.rank(), a_org.rank() ); - ASSERT_EQ( a_h.rank(), a_h2.rank() ); - ASSERT_EQ( a_h.rank(), a_h3.rank() ); - ASSERT_EQ( a_h.rank(), a_d.rank() ); - ASSERT_EQ( a_org(5), a_h3(5) ); + Kokkos::DynRankView a_h = + a_org; + auto a_h2 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_h); + auto a_d = Kokkos::create_mirror_view_and_copy(DeviceType(), a_h); + auto a_h3 = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a_d); + + int equal_ptr_h_h2 = a_h.data() == a_h2.data() ? 1 : 0; + int equal_ptr_h_d = a_h.data() == a_d.data() ? 1 : 0; + int equal_ptr_h2_d = a_h2.data() == a_d.data() ? 1 : 0; + int equal_ptr_h3_d = a_h3.data() == a_d.data() ? 1 : 0; + + int is_same_memspace = + std::is_same::value + ? 1 + : 0; + ASSERT_EQ(equal_ptr_h_h2, 1); + ASSERT_EQ(equal_ptr_h_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h2_d, is_same_memspace); + ASSERT_EQ(equal_ptr_h3_d, is_same_memspace); + + ASSERT_EQ(a_h.extent(0), a_h3.extent(0)); + ASSERT_EQ(a_h.extent(0), a_h2.extent(0)); + ASSERT_EQ(a_h.extent(0), a_d.extent(0)); + ASSERT_EQ(a_h.rank(), a_org.rank()); + ASSERT_EQ(a_h.rank(), a_h2.rank()); + ASSERT_EQ(a_h.rank(), a_h3.rank()); + ASSERT_EQ(a_h.rank(), a_d.rank()); + ASSERT_EQ(a_org(5), a_h3(5)); } } - static void run_test_scalar() - { - typedef typename dView0::HostMirror hView0 ; //HostMirror of DynRankView is a DynRankView + static void run_test_scalar() { + typedef typename dView0::HostMirror + hView0; // HostMirror of DynRankView is a DynRankView - dView0 dx , dy ; - hView0 hx , hy ; + dView0 dx, dy; + hView0 hx, hy; - dx = dView0( "dx" ); - dy = dView0( "dy" ); + dx = dView0("dx"); + dy = dView0("dy"); - hx = Kokkos::create_mirror( dx ); - hy = Kokkos::create_mirror( dy ); + hx = Kokkos::create_mirror(dx); + hy = Kokkos::create_mirror(dy); - hx() = 1 ; + hx() = 1; - Kokkos::deep_copy( dx , hx ); - Kokkos::deep_copy( dy , dx ); - Kokkos::deep_copy( hy , dy ); + Kokkos::deep_copy(dx, hx); + Kokkos::deep_copy(dy, dx); + Kokkos::deep_copy(hy, dy); - ASSERT_EQ( hx(), hy() ); - ASSERT_EQ( dx.rank() , hx.rank() ); - ASSERT_EQ( dy.rank() , hy.rank() ); + ASSERT_EQ(hx(), hy()); + ASSERT_EQ(dx.rank(), hx.rank()); + ASSERT_EQ(dy.rank(), hy.rank()); - //View - DynRankView Interoperability tests - // deep_copy DynRankView to View + // View - DynRankView Interoperability tests + // deep_copy DynRankView to View View0 vx("vx"); - Kokkos::deep_copy( vx , dx ); - ASSERT_EQ( rank(dx) , rank(vx) ); + Kokkos::deep_copy(vx, dx); + ASSERT_EQ(rank(dx), rank(vx)); View0 vy("vy"); - Kokkos::deep_copy( vy , dy ); - ASSERT_EQ( rank(dy) , rank(vy) ); + Kokkos::deep_copy(vy, dy); + ASSERT_EQ(rank(dy), rank(vy)); - // deep_copy View to DynRankView + // deep_copy View to DynRankView dView0 dxx("dxx"); - Kokkos::deep_copy( dxx , vx ); - ASSERT_EQ( rank(dxx) , rank(vx) ); - + Kokkos::deep_copy(dxx, vx); + ASSERT_EQ(rank(dxx), rank(vx)); View7 vcast = dx.ConstDownCast(); - ASSERT_EQ( dx.extent(0) , vcast.extent(0) ); - ASSERT_EQ( dx.extent(1) , vcast.extent(1) ); - ASSERT_EQ( dx.extent(2) , vcast.extent(2) ); - ASSERT_EQ( dx.extent(3) , vcast.extent(3) ); - ASSERT_EQ( dx.extent(4) , vcast.extent(4) ); - - View7 vcast1( dy.ConstDownCast() ); - ASSERT_EQ( dy.extent(0) , vcast1.extent(0) ); - ASSERT_EQ( dy.extent(1) , vcast1.extent(1) ); - ASSERT_EQ( dy.extent(2) , vcast1.extent(2) ); - ASSERT_EQ( dy.extent(3) , vcast1.extent(3) ); - ASSERT_EQ( dy.extent(4) , vcast1.extent(4) ); - - //View - DynRankView Interoperability tests - // copy View to DynRankView - dView0 dfromvx( vx ); - auto hmx = Kokkos::create_mirror_view(dfromvx) ; - Kokkos::deep_copy(hmx , dfromvx); - auto hvx = Kokkos::create_mirror_view(vx) ; - Kokkos::deep_copy(hvx , vx); - ASSERT_EQ( rank(hvx) , rank(hmx) ); - ASSERT_EQ( hvx.extent(0) , hmx.extent(0) ); - ASSERT_EQ( hvx.extent(1) , hmx.extent(1) ); - - // copy-assign View to DynRankView - dView0 dfromvy = vy ; - auto hmy = Kokkos::create_mirror_view(dfromvy) ; - Kokkos::deep_copy(hmy , dfromvy); - auto hvy = Kokkos::create_mirror_view(vy) ; - Kokkos::deep_copy(hvy , vy); - ASSERT_EQ( rank(hvy) , rank(hmy) ); - ASSERT_EQ( hvy.extent(0) , hmy.extent(0) ); - ASSERT_EQ( hvy.extent(1) , hmy.extent(1) ); - - - View7 vtest1("vtest1",2,2,2,2,2,2,2); - dView0 dfromv1( vtest1 ); - ASSERT_EQ( dfromv1.rank() , vtest1.Rank ); - ASSERT_EQ( dfromv1.extent(0) , vtest1.extent(0) ); - ASSERT_EQ( dfromv1.extent(1) , vtest1.extent(1) ); - ASSERT_EQ( dfromv1.use_count() , vtest1.use_count() ); - - dView0 dfromv2( vcast ); - ASSERT_EQ( dfromv2.rank() , vcast.Rank ); - ASSERT_EQ( dfromv2.extent(0) , vcast.extent(0) ); - ASSERT_EQ( dfromv2.extent(1) , vcast.extent(1) ); - ASSERT_EQ( dfromv2.use_count() , vcast.use_count() ); + ASSERT_EQ(dx.extent(0), vcast.extent(0)); + ASSERT_EQ(dx.extent(1), vcast.extent(1)); + ASSERT_EQ(dx.extent(2), vcast.extent(2)); + ASSERT_EQ(dx.extent(3), vcast.extent(3)); + ASSERT_EQ(dx.extent(4), vcast.extent(4)); + + View7 vcast1(dy.ConstDownCast()); + ASSERT_EQ(dy.extent(0), vcast1.extent(0)); + ASSERT_EQ(dy.extent(1), vcast1.extent(1)); + ASSERT_EQ(dy.extent(2), vcast1.extent(2)); + ASSERT_EQ(dy.extent(3), vcast1.extent(3)); + ASSERT_EQ(dy.extent(4), vcast1.extent(4)); + + // View - DynRankView Interoperability tests + // copy View to DynRankView + dView0 dfromvx(vx); + auto hmx = Kokkos::create_mirror_view(dfromvx); + Kokkos::deep_copy(hmx, dfromvx); + auto hvx = Kokkos::create_mirror_view(vx); + Kokkos::deep_copy(hvx, vx); + ASSERT_EQ(rank(hvx), rank(hmx)); + ASSERT_EQ(hvx.extent(0), hmx.extent(0)); + ASSERT_EQ(hvx.extent(1), hmx.extent(1)); + + // copy-assign View to DynRankView + dView0 dfromvy = vy; + auto hmy = Kokkos::create_mirror_view(dfromvy); + Kokkos::deep_copy(hmy, dfromvy); + auto hvy = Kokkos::create_mirror_view(vy); + Kokkos::deep_copy(hvy, vy); + ASSERT_EQ(rank(hvy), rank(hmy)); + ASSERT_EQ(hvy.extent(0), hmy.extent(0)); + ASSERT_EQ(hvy.extent(1), hmy.extent(1)); + + View7 vtest1("vtest1", 2, 2, 2, 2, 2, 2, 2); + dView0 dfromv1(vtest1); + ASSERT_EQ(dfromv1.rank(), vtest1.Rank); + ASSERT_EQ(dfromv1.extent(0), vtest1.extent(0)); + ASSERT_EQ(dfromv1.extent(1), vtest1.extent(1)); + ASSERT_EQ(dfromv1.use_count(), vtest1.use_count()); + + dView0 dfromv2(vcast); + ASSERT_EQ(dfromv2.rank(), vcast.Rank); + ASSERT_EQ(dfromv2.extent(0), vcast.extent(0)); + ASSERT_EQ(dfromv2.extent(1), vcast.extent(1)); + ASSERT_EQ(dfromv2.use_count(), vcast.use_count()); dView0 dfromv3 = vcast1; - ASSERT_EQ( dfromv3.rank() , vcast1.Rank ); - ASSERT_EQ( dfromv3.extent(0) , vcast1.extent(0) ); - ASSERT_EQ( dfromv3.extent(1) , vcast1.extent(1) ); - ASSERT_EQ( dfromv3.use_count() , vcast1.use_count() ); + ASSERT_EQ(dfromv3.rank(), vcast1.Rank); + ASSERT_EQ(dfromv3.extent(0), vcast1.extent(0)); + ASSERT_EQ(dfromv3.extent(1), vcast1.extent(1)); + ASSERT_EQ(dfromv3.use_count(), vcast1.use_count()); } - static void run_test() - { + static void run_test() { // mfh 14 Feb 2014: This test doesn't actually create instances of // these types. In order to avoid "declared but unused typedef" // warnings, we declare empty instances of these types, with the // usual "(void)" marker to avoid compiler warnings for unused // variables. - typedef typename dView0::HostMirror hView0 ; + typedef typename dView0::HostMirror hView0; { hView0 thing; - (void) thing; + (void)thing; } - dView0 d_uninitialized(Kokkos::ViewAllocateWithoutInitializing("uninit"),10,20); - ASSERT_TRUE( d_uninitialized.data() != nullptr ); - ASSERT_EQ( d_uninitialized.rank() , 2 ); - ASSERT_EQ( d_uninitialized.extent(0) , 10 ); - ASSERT_EQ( d_uninitialized.extent(1) , 20 ); - ASSERT_EQ( d_uninitialized.extent(2) , 1 ); - - dView0 dx , dy , dz ; - hView0 hx , hy , hz ; - - ASSERT_TRUE( Kokkos::is_dyn_rank_view::value ); - ASSERT_FALSE( Kokkos::is_dyn_rank_view< Kokkos::View >::value ); - - ASSERT_TRUE( dx.data() == 0 ); //Okay with UVM - ASSERT_TRUE( dy.data() == 0 ); //Okay with UVM - ASSERT_TRUE( dz.data() == 0 ); //Okay with UVM - ASSERT_TRUE( hx.data() == 0 ); - ASSERT_TRUE( hy.data() == 0 ); - ASSERT_TRUE( hz.data() == 0 ); - ASSERT_EQ( dx.extent(0) , 0u ); //Okay with UVM - ASSERT_EQ( dy.extent(0) , 0u ); //Okay with UVM - ASSERT_EQ( dz.extent(0) , 0u ); //Okay with UVM - ASSERT_EQ( hx.extent(0) , 0u ); - ASSERT_EQ( hy.extent(0) , 0u ); - ASSERT_EQ( hz.extent(0) , 0u ); - ASSERT_EQ( dx.rank() , 0u ); //Okay with UVM - ASSERT_EQ( hx.rank() , 0u ); - - dx = dView0( "dx" , N1 , N2 , N3 ); - dy = dView0( "dy" , N1 , N2 , N3 ); - - hx = hView0( "hx" , N1 , N2 , N3 ); - hy = hView0( "hy" , N1 , N2 , N3 ); - - ASSERT_EQ( dx.extent(0) , unsigned(N1) ); //Okay with UVM - ASSERT_EQ( dy.extent(0) , unsigned(N1) ); //Okay with UVM - ASSERT_EQ( hx.extent(0) , unsigned(N1) ); - ASSERT_EQ( hy.extent(0) , unsigned(N1) ); - ASSERT_EQ( dx.rank() , 3 ); //Okay with UVM - ASSERT_EQ( hx.rank() , 3 ); - - dx = dView0( "dx" , N0 , N1 , N2 , N3 ); - dy = dView0( "dy" , N0 , N1 , N2 , N3 ); - hx = hView0( "hx" , N0 , N1 , N2 , N3 ); - hy = hView0( "hy" , N0 , N1 , N2 , N3 ); - - ASSERT_EQ( dx.extent(0) , unsigned(N0) ); - ASSERT_EQ( dy.extent(0) , unsigned(N0) ); - ASSERT_EQ( hx.extent(0) , unsigned(N0) ); - ASSERT_EQ( hy.extent(0) , unsigned(N0) ); - ASSERT_EQ( dx.rank() , 4 ); - ASSERT_EQ( dy.rank() , 4 ); - ASSERT_EQ( hx.rank() , 4 ); - ASSERT_EQ( hy.rank() , 4 ); - - ASSERT_EQ( dx.use_count() , size_t(1) ); + dView0 d_uninitialized(Kokkos::ViewAllocateWithoutInitializing("uninit"), + 10, 20); + ASSERT_TRUE(d_uninitialized.data() != nullptr); + ASSERT_EQ(d_uninitialized.rank(), 2); + ASSERT_EQ(d_uninitialized.extent(0), 10); + ASSERT_EQ(d_uninitialized.extent(1), 20); + ASSERT_EQ(d_uninitialized.extent(2), 1); + + dView0 dx, dy, dz; + hView0 hx, hy, hz; + + ASSERT_TRUE(Kokkos::is_dyn_rank_view::value); + ASSERT_FALSE(Kokkos::is_dyn_rank_view >::value); + + ASSERT_TRUE(dx.data() == 0); // Okay with UVM + ASSERT_TRUE(dy.data() == 0); // Okay with UVM + ASSERT_TRUE(dz.data() == 0); // Okay with UVM + ASSERT_TRUE(hx.data() == 0); + ASSERT_TRUE(hy.data() == 0); + ASSERT_TRUE(hz.data() == 0); + ASSERT_EQ(dx.extent(0), 0u); // Okay with UVM + ASSERT_EQ(dy.extent(0), 0u); // Okay with UVM + ASSERT_EQ(dz.extent(0), 0u); // Okay with UVM + ASSERT_EQ(hx.extent(0), 0u); + ASSERT_EQ(hy.extent(0), 0u); + ASSERT_EQ(hz.extent(0), 0u); + ASSERT_EQ(dx.rank(), 0u); // Okay with UVM + ASSERT_EQ(hx.rank(), 0u); + + dx = dView0("dx", N1, N2, N3); + dy = dView0("dy", N1, N2, N3); + + hx = hView0("hx", N1, N2, N3); + hy = hView0("hy", N1, N2, N3); + + ASSERT_EQ(dx.extent(0), unsigned(N1)); // Okay with UVM + ASSERT_EQ(dy.extent(0), unsigned(N1)); // Okay with UVM + ASSERT_EQ(hx.extent(0), unsigned(N1)); + ASSERT_EQ(hy.extent(0), unsigned(N1)); + ASSERT_EQ(dx.rank(), 3); // Okay with UVM + ASSERT_EQ(hx.rank(), 3); + + dx = dView0("dx", N0, N1, N2, N3); + dy = dView0("dy", N0, N1, N2, N3); + hx = hView0("hx", N0, N1, N2, N3); + hy = hView0("hy", N0, N1, N2, N3); + + ASSERT_EQ(dx.extent(0), unsigned(N0)); + ASSERT_EQ(dy.extent(0), unsigned(N0)); + ASSERT_EQ(hx.extent(0), unsigned(N0)); + ASSERT_EQ(hy.extent(0), unsigned(N0)); + ASSERT_EQ(dx.rank(), 4); + ASSERT_EQ(dy.rank(), 4); + ASSERT_EQ(hx.rank(), 4); + ASSERT_EQ(hy.rank(), 4); + + ASSERT_EQ(dx.use_count(), size_t(1)); dView0_unmanaged unmanaged_dx = dx; - ASSERT_EQ( dx.use_count() , size_t(1) ); - - - dView0_unmanaged unmanaged_from_ptr_dx = dView0_unmanaged(dx.data(), - dx.extent(0), - dx.extent(1), - dx.extent(2), - dx.extent(3)); + ASSERT_EQ(dx.use_count(), size_t(1)); + dView0_unmanaged unmanaged_from_ptr_dx = dView0_unmanaged( + dx.data(), dx.extent(0), dx.extent(1), dx.extent(2), dx.extent(3)); { // Destruction of this view should be harmless - const_dView0 unmanaged_from_ptr_const_dx( dx.data() , - dx.extent(0) , - dx.extent(1) , - dx.extent(2) , - dx.extent(3) ); + const_dView0 unmanaged_from_ptr_const_dx( + dx.data(), dx.extent(0), dx.extent(1), dx.extent(2), dx.extent(3)); } - const_dView0 const_dx = dx ; - ASSERT_EQ( dx.use_count() , size_t(2) ); + const_dView0 const_dx = dx; + ASSERT_EQ(dx.use_count(), size_t(2)); { const_dView0 const_dx2; const_dx2 = const_dx; - ASSERT_EQ( dx.use_count() , size_t(3) ); + ASSERT_EQ(dx.use_count(), size_t(3)); const_dx2 = dy; - ASSERT_EQ( dx.use_count() , size_t(2) ); + ASSERT_EQ(dx.use_count(), size_t(2)); const_dView0 const_dx3(dx); - ASSERT_EQ( dx.use_count() , size_t(3) ); - + ASSERT_EQ(dx.use_count(), size_t(3)); + dView0_unmanaged dx4_unmanaged(dx); - ASSERT_EQ( dx.use_count() , size_t(3) ); + ASSERT_EQ(dx.use_count(), size_t(3)); } - ASSERT_EQ( dx.use_count() , size_t(2) ); - + ASSERT_EQ(dx.use_count(), size_t(2)); - ASSERT_FALSE( dx.data() == 0 ); - ASSERT_FALSE( const_dx.data() == 0 ); - ASSERT_FALSE( unmanaged_dx.data() == 0 ); - ASSERT_FALSE( unmanaged_from_ptr_dx.data() == 0 ); - ASSERT_FALSE( dy.data() == 0 ); - ASSERT_NE( dx , dy ); + ASSERT_FALSE(dx.data() == 0); + ASSERT_FALSE(const_dx.data() == 0); + ASSERT_FALSE(unmanaged_dx.data() == 0); + ASSERT_FALSE(unmanaged_from_ptr_dx.data() == 0); + ASSERT_FALSE(dy.data() == 0); + ASSERT_NE(dx, dy); - ASSERT_EQ( dx.extent(0) , unsigned(N0) ); - ASSERT_EQ( dx.extent(1) , unsigned(N1) ); - ASSERT_EQ( dx.extent(2) , unsigned(N2) ); - ASSERT_EQ( dx.extent(3) , unsigned(N3) ); + ASSERT_EQ(dx.extent(0), unsigned(N0)); + ASSERT_EQ(dx.extent(1), unsigned(N1)); + ASSERT_EQ(dx.extent(2), unsigned(N2)); + ASSERT_EQ(dx.extent(3), unsigned(N3)); - ASSERT_EQ( dy.extent(0) , unsigned(N0) ); - ASSERT_EQ( dy.extent(1) , unsigned(N1) ); - ASSERT_EQ( dy.extent(2) , unsigned(N2) ); - ASSERT_EQ( dy.extent(3) , unsigned(N3) ); + ASSERT_EQ(dy.extent(0), unsigned(N0)); + ASSERT_EQ(dy.extent(1), unsigned(N1)); + ASSERT_EQ(dy.extent(2), unsigned(N2)); + ASSERT_EQ(dy.extent(3), unsigned(N3)); - ASSERT_EQ( unmanaged_from_ptr_dx.span(),unsigned(N0)*unsigned(N1)*unsigned(N2)*unsigned(N3) ); + ASSERT_EQ(unmanaged_from_ptr_dx.span(), + unsigned(N0) * unsigned(N1) * unsigned(N2) * unsigned(N3)); - hx = Kokkos::create_mirror( dx ); - hy = Kokkos::create_mirror( dy ); + hx = Kokkos::create_mirror(dx); + hy = Kokkos::create_mirror(dy); - ASSERT_EQ( hx.rank() , dx.rank() ); - ASSERT_EQ( hy.rank() , dy.rank() ); + ASSERT_EQ(hx.rank(), dx.rank()); + ASSERT_EQ(hy.rank(), dy.rank()); - ASSERT_EQ( hx.extent(0) , unsigned(N0) ); - ASSERT_EQ( hx.extent(1) , unsigned(N1) ); - ASSERT_EQ( hx.extent(2) , unsigned(N2) ); - ASSERT_EQ( hx.extent(3) , unsigned(N3) ); + ASSERT_EQ(hx.extent(0), unsigned(N0)); + ASSERT_EQ(hx.extent(1), unsigned(N1)); + ASSERT_EQ(hx.extent(2), unsigned(N2)); + ASSERT_EQ(hx.extent(3), unsigned(N3)); - ASSERT_EQ( hy.extent(0) , unsigned(N0) ); - ASSERT_EQ( hy.extent(1) , unsigned(N1) ); - ASSERT_EQ( hy.extent(2) , unsigned(N2) ); - ASSERT_EQ( hy.extent(3) , unsigned(N3) ); + ASSERT_EQ(hy.extent(0), unsigned(N0)); + ASSERT_EQ(hy.extent(1), unsigned(N1)); + ASSERT_EQ(hy.extent(2), unsigned(N2)); + ASSERT_EQ(hy.extent(3), unsigned(N3)); // T v1 = hx() ; // Generates compile error as intended // T v2 = hx(0,0) ; // Generates compile error as intended @@ -1265,365 +1263,422 @@ public: // Testing with synchronous deep copy { - size_t count = 0 ; - for ( size_t ip = 0 ; ip < N0 ; ++ip ) { - for ( size_t i1 = 0 ; i1 < hx.extent(1) ; ++i1 ) { - for ( size_t i2 = 0 ; i2 < hx.extent(2) ; ++i2 ) { - for ( size_t i3 = 0 ; i3 < hx.extent(3) ; ++i3 ) { - hx(ip,i1,i2,i3) = ++count ; - }}}} - - Kokkos::deep_copy( dx , hx ); - Kokkos::deep_copy( dy , dx ); - Kokkos::deep_copy( hy , dy ); + size_t count = 0; + for (size_t ip = 0; ip < N0; ++ip) { + for (size_t i1 = 0; i1 < hx.extent(1); ++i1) { + for (size_t i2 = 0; i2 < hx.extent(2); ++i2) { + for (size_t i3 = 0; i3 < hx.extent(3); ++i3) { + hx(ip, i1, i2, i3) = ++count; + } + } + } + } + + Kokkos::deep_copy(dx, hx); + Kokkos::deep_copy(dy, dx); + Kokkos::deep_copy(hy, dy); Kokkos::fence(); - for ( size_t ip = 0 ; ip < N0 ; ++ip ) { - for ( size_t i1 = 0 ; i1 < N1 ; ++i1 ) { - for ( size_t i2 = 0 ; i2 < N2 ; ++i2 ) { - for ( size_t i3 = 0 ; i3 < N3 ; ++i3 ) { - { ASSERT_EQ( hx(ip,i1,i2,i3) , hy(ip,i1,i2,i3) ); } - }}}} - - Kokkos::deep_copy( dx , T(0) ); - Kokkos::deep_copy( hx , dx ); + for (size_t ip = 0; ip < N0; ++ip) { + for (size_t i1 = 0; i1 < N1; ++i1) { + for (size_t i2 = 0; i2 < N2; ++i2) { + for (size_t i3 = 0; i3 < N3; ++i3) { + { + ASSERT_EQ(hx(ip, i1, i2, i3), hy(ip, i1, i2, i3)); + } + } + } + } + } + + Kokkos::deep_copy(dx, T(0)); + Kokkos::deep_copy(hx, dx); Kokkos::fence(); - for ( size_t ip = 0 ; ip < N0 ; ++ip ) { - for ( size_t i1 = 0 ; i1 < N1 ; ++i1 ) { - for ( size_t i2 = 0 ; i2 < N2 ; ++i2 ) { - for ( size_t i3 = 0 ; i3 < N3 ; ++i3 ) { - { ASSERT_EQ( hx(ip,i1,i2,i3) , T(0) ); } - }}}} -// ASSERT_EQ( hx(0,0,0,0,0,0,0,0) , T(0) ); //Test rank8 op behaves properly - if implemented + for (size_t ip = 0; ip < N0; ++ip) { + for (size_t i1 = 0; i1 < N1; ++i1) { + for (size_t i2 = 0; i2 < N2; ++i2) { + for (size_t i3 = 0; i3 < N3; ++i3) { + { + ASSERT_EQ(hx(ip, i1, i2, i3), T(0)); + } + } + } + } + } + // ASSERT_EQ( hx(0,0,0,0,0,0,0,0) , T(0) ); //Test rank8 op behaves + // properly - if implemented } - dz = dx ; ASSERT_EQ( dx, dz); ASSERT_NE( dy, dz); - dz = dy ; ASSERT_EQ( dy, dz); ASSERT_NE( dx, dz); + dz = dx; + ASSERT_EQ(dx, dz); + ASSERT_NE(dy, dz); + dz = dy; + ASSERT_EQ(dy, dz); + ASSERT_NE(dx, dz); dx = dView0(); - ASSERT_TRUE( dx.data() == 0 ); - ASSERT_FALSE( dy.data() == 0 ); - ASSERT_FALSE( dz.data() == 0 ); + ASSERT_TRUE(dx.data() == 0); + ASSERT_FALSE(dy.data() == 0); + ASSERT_FALSE(dz.data() == 0); dy = dView0(); - ASSERT_TRUE( dx.data() == 0 ); - ASSERT_TRUE( dy.data() == 0 ); - ASSERT_FALSE( dz.data() == 0 ); + ASSERT_TRUE(dx.data() == 0); + ASSERT_TRUE(dy.data() == 0); + ASSERT_FALSE(dz.data() == 0); dz = dView0(); - ASSERT_TRUE( dx.data() == 0 ); - ASSERT_TRUE( dy.data() == 0 ); - ASSERT_TRUE( dz.data() == 0 ); + ASSERT_TRUE(dx.data() == 0); + ASSERT_TRUE(dy.data() == 0); + ASSERT_TRUE(dz.data() == 0); - //View - DynRankView Interoperability tests + // View - DynRankView Interoperability tests // deep_copy from view to dynrankview const int testdim = 4; - dView0 dxx("dxx",testdim); - View1 vxx("vxx",testdim); - auto hvxx = Kokkos::create_mirror_view(vxx); - for (int i = 0; i < testdim; ++i) - { hvxx(i) = i; } - Kokkos::deep_copy(vxx,hvxx); - Kokkos::deep_copy(dxx,vxx); + dView0 dxx("dxx", testdim); + View1 vxx("vxx", testdim); + auto hvxx = Kokkos::create_mirror_view(vxx); + for (int i = 0; i < testdim; ++i) { + hvxx(i) = i; + } + Kokkos::deep_copy(vxx, hvxx); + Kokkos::deep_copy(dxx, vxx); auto hdxx = Kokkos::create_mirror_view(dxx); - Kokkos::deep_copy(hdxx,dxx); - for (int i = 0; i < testdim; ++i) - { ASSERT_EQ( hvxx(i) , hdxx(i) ); } + Kokkos::deep_copy(hdxx, dxx); + for (int i = 0; i < testdim; ++i) { + ASSERT_EQ(hvxx(i), hdxx(i)); + } - ASSERT_EQ( rank(hdxx) , rank(hvxx) ); - ASSERT_EQ( hdxx.extent(0) , testdim ); - ASSERT_EQ( hdxx.extent(0) , hvxx.extent(0) ); + ASSERT_EQ(rank(hdxx), rank(hvxx)); + ASSERT_EQ(hdxx.extent(0), testdim); + ASSERT_EQ(hdxx.extent(0), hvxx.extent(0)); // deep_copy from dynrankview to view - View1 vdxx("vdxx",testdim); + View1 vdxx("vdxx", testdim); auto hvdxx = Kokkos::create_mirror_view(vdxx); - Kokkos::deep_copy(hvdxx , hdxx); - ASSERT_EQ( rank(hdxx) , rank(hvdxx) ); - ASSERT_EQ( hvdxx.extent(0) , testdim ); - ASSERT_EQ( hdxx.extent(0) , hvdxx.extent(0) ); - for (int i = 0; i < testdim; ++i) - { ASSERT_EQ( hvxx(i) , hvdxx(i) ); } + Kokkos::deep_copy(hvdxx, hdxx); + ASSERT_EQ(rank(hdxx), rank(hvdxx)); + ASSERT_EQ(hvdxx.extent(0), testdim); + ASSERT_EQ(hdxx.extent(0), hvdxx.extent(0)); + for (int i = 0; i < testdim; ++i) { + ASSERT_EQ(hvxx(i), hvdxx(i)); + } } - typedef T DataType ; + typedef T DataType; - static void - check_auto_conversion_to_const( - const Kokkos::DynRankView< const DataType , device > & arg_const , - const Kokkos::DynRankView< DataType , device > & arg ) - { - ASSERT_TRUE( arg_const == arg ); + static void check_auto_conversion_to_const( + const Kokkos::DynRankView& arg_const, + const Kokkos::DynRankView& arg) { + ASSERT_TRUE(arg_const == arg); } - static void run_test_const() - { - typedef Kokkos::DynRankView< DataType , device > typeX ; - typedef Kokkos::DynRankView< const DataType , device > const_typeX ; - typedef Kokkos::DynRankView< const DataType , device , Kokkos::MemoryRandomAccess > const_typeR ; - typeX x( "X", 2 ); - const_typeX xc = x ; - const_typeR xr = x ; + static void run_test_const() { + typedef Kokkos::DynRankView typeX; + typedef Kokkos::DynRankView const_typeX; + typedef Kokkos::DynRankView + const_typeR; + typeX x("X", 2); + const_typeX xc = x; + const_typeR xr = x; - ASSERT_TRUE( xc == x ); - ASSERT_TRUE( x == xc ); + ASSERT_TRUE(xc == x); + ASSERT_TRUE(x == xc); // For CUDA the constant random access View does not return // an lvalue reference due to retrieving through texture cache // therefore not allowed to query the underlying pointer. #if defined(KOKKOS_ENABLE_CUDA) - if ( ! std::is_same< typename device::execution_space , Kokkos::Cuda >::value ) + if (!std::is_same::value) #endif { - ASSERT_TRUE( x.data() == xr.data() ); + ASSERT_TRUE(x.data() == xr.data()); } // typeX xf = xc ; // setting non-const from const must not compile - check_auto_conversion_to_const( x , x ); + check_auto_conversion_to_const(x, x); } - - static void run_test_subview() - { - typedef Kokkos::DynRankView< const T , device > cdView ; - typedef Kokkos::DynRankView< T , device > dView ; - // LayoutStride required for all returned DynRankView subdynrankview's - typedef Kokkos::DynRankView< T , Kokkos::LayoutStride , device > sdView ; - - dView0 d0( "d0" ); - cdView s0 = d0 ; - - // N0 = 1000,N1 = 3,N2 = 5,N3 = 7 - unsigned order[] = { 6,5,4,3,2,1,0 }, dimen[] = { N0, N1, N2, 2, 2, 2, 2 }; //LayoutRight equivalent - sdView d7( "d7" , Kokkos::LayoutStride::order_dimensions(7, order, dimen) ); - ASSERT_EQ( d7.rank() , 7 ); - - sdView ds0 = Kokkos::subdynrankview( d7 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ); - ASSERT_EQ( ds0.rank() , 0 ); - -//Basic test - ALL - sdView dsALL = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() ); - ASSERT_EQ( dsALL.rank() , 7 ); - -// Send a value to final rank returning rank 6 subview - sdView dsm1 = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , 1 ); - ASSERT_EQ( dsm1.rank() , 6 ); - -// Send a std::pair as argument to a rank - sdView dssp = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , std::pair(1,2) ); - ASSERT_EQ( dssp.rank() , 7 ); - -// Send a kokkos::pair as argument to a rank; take default layout as input - dView0 dd0("dd0" , N0 , N1 , N2 , 2 , 2 , 2 , 2 ); //default layout - ASSERT_EQ( dd0.rank() , 7 ); - sdView dtkp = Kokkos::subdynrankview( dd0 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) ); - ASSERT_EQ( dtkp.rank() , 7 ); - -// Return rank 7 subview, taking a pair as one argument, layout stride input - sdView ds7 = Kokkos::subdynrankview( d7 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) ); - ASSERT_EQ( ds7.rank() , 7 ); - -// Default Layout DynRankView - dView dv6("dv6" , N0 , N1 , N2 , N3 , 2 , 2 ); - ASSERT_EQ( dv6.rank() , 6 ); - -// DynRankView with LayoutRight - typedef Kokkos::DynRankView< T , Kokkos::LayoutRight , device > drView ; - drView dr5( "dr5" , N0 , N1 , N2 , 2 , 2 ); - ASSERT_EQ( dr5.rank() , 5 ); - -// LayoutStride but arranged as LayoutRight - // NOTE: unused arg_layout dimensions must be set toKOKKOS_INVALID_INDEX so that - // rank deduction can properly take place - unsigned order5[] = { 4,3,2,1,0 }, dimen5[] = { N0, N1, N2, 2, 2 }; - Kokkos::LayoutStride ls = Kokkos::LayoutStride::order_dimensions(5, order5, dimen5); - ls.dimension[5] =KOKKOS_INVALID_INDEX; - ls.dimension[6] =KOKKOS_INVALID_INDEX; - ls.dimension[7] =KOKKOS_INVALID_INDEX; + static void run_test_subview() { + typedef Kokkos::DynRankView cdView; + typedef Kokkos::DynRankView dView; + // LayoutStride required for all returned DynRankView subdynrankview's + typedef Kokkos::DynRankView sdView; + + dView0 d0("d0"); + cdView s0 = d0; + + // N0 = 1000,N1 = 3,N2 = 5,N3 = 7 + unsigned order[] = {6, 5, 4, 3, 2, 1, 0}, + dimen[] = {N0, N1, N2, 2, 2, 2, 2}; // LayoutRight equivalent + sdView d7("d7", Kokkos::LayoutStride::order_dimensions(7, order, dimen)); + ASSERT_EQ(d7.rank(), 7); + + sdView ds0 = Kokkos::subdynrankview(d7, 1, 1, 1, 1, 1, 1, 1); + ASSERT_EQ(ds0.rank(), 0); + + // Basic test - ALL + sdView dsALL = Kokkos::subdynrankview( + d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(dsALL.rank(), 7); + + // Send a value to final rank returning rank 6 subview + sdView dsm1 = + Kokkos::subdynrankview(d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), 1); + ASSERT_EQ(dsm1.rank(), 6); + + // Send a std::pair as argument to a rank + sdView dssp = Kokkos::subdynrankview( + d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), std::pair(1, 2)); + ASSERT_EQ(dssp.rank(), 7); + + // Send a kokkos::pair as argument to a rank; take default layout as input + dView0 dd0("dd0", N0, N1, N2, 2, 2, 2, 2); // default layout + ASSERT_EQ(dd0.rank(), 7); + sdView dtkp = Kokkos::subdynrankview( + dd0, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::pair(0, 1)); + ASSERT_EQ(dtkp.rank(), 7); + + // Return rank 7 subview, taking a pair as one argument, layout stride input + sdView ds7 = Kokkos::subdynrankview( + d7, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), Kokkos::pair(0, 1)); + ASSERT_EQ(ds7.rank(), 7); + + // Default Layout DynRankView + dView dv6("dv6", N0, N1, N2, N3, 2, 2); + ASSERT_EQ(dv6.rank(), 6); + + // DynRankView with LayoutRight + typedef Kokkos::DynRankView drView; + drView dr5("dr5", N0, N1, N2, 2, 2); + ASSERT_EQ(dr5.rank(), 5); + + // LayoutStride but arranged as LayoutRight + // NOTE: unused arg_layout dimensions must be set toKOKKOS_INVALID_INDEX so + // that + // rank deduction can properly take place + unsigned order5[] = {4, 3, 2, 1, 0}, dimen5[] = {N0, N1, N2, 2, 2}; + Kokkos::LayoutStride ls = + Kokkos::LayoutStride::order_dimensions(5, order5, dimen5); + ls.dimension[5] = KOKKOS_INVALID_INDEX; + ls.dimension[6] = KOKKOS_INVALID_INDEX; + ls.dimension[7] = KOKKOS_INVALID_INDEX; sdView d5("d5", ls); - ASSERT_EQ( d5.rank() , 5 ); - -// LayoutStride arranged as LayoutRight - commented out as example that fails unit test -// unsigned order5[] = { 4,3,2,1,0 }, dimen5[] = { N0, N1, N2, 2, 2 }; -// sdView d5( "d5" , Kokkos::LayoutStride::order_dimensions(5, order5, dimen5) ); -// -// Fails the following unit test: -// ASSERT_EQ( d5.rank() , dr5.rank() ); -// -// Explanation: In construction of the Kokkos::LayoutStride below, since the -// remaining dimensions are not specified, they will default to values of 0 -// rather thanKOKKOS_INVALID_INDEX. -// When passed to the DynRankView constructor the default dimensions (of 0) -// will be counted toward the dynamic rank and returning an incorrect value -// (i.e. rank 7 rather than 5). - -// Check LayoutRight dr5 and LayoutStride d5 dimensions agree (as they should) - ASSERT_EQ( d5.extent(0) , dr5.extent(0) ); - ASSERT_EQ( d5.extent(1) , dr5.extent(1) ); - ASSERT_EQ( d5.extent(2) , dr5.extent(2) ); - ASSERT_EQ( d5.extent(3) , dr5.extent(3) ); - ASSERT_EQ( d5.extent(4) , dr5.extent(4) ); - ASSERT_EQ( d5.extent(5) , dr5.extent(5) ); - ASSERT_EQ( d5.rank() , dr5.rank() ); - -// Rank 5 subview of rank 5 dynamic rank view, layout stride input - sdView ds5 = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) ); - ASSERT_EQ( ds5.rank() , 5 ); - -// Pass in extra ALL arguments beyond the rank of the DynRank View. -// This behavior is allowed - ignore the extra ALL arguments when -// the src.rank() < number of arguments, but be careful! - sdView ds5plus = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::pair(0,1) , Kokkos::ALL() ); - - ASSERT_EQ( ds5.rank() , ds5plus.rank() ); - ASSERT_EQ( ds5.extent(0) , ds5plus.extent(0) ); - ASSERT_EQ( ds5.extent(4) , ds5plus.extent(4) ); - ASSERT_EQ( ds5.extent(5) , ds5plus.extent(5) ); - -#if ! defined( KOKKOS_ENABLE_CUDA ) || defined ( KOKKOS_ENABLE_CUDA_UVM ) - ASSERT_EQ( & ds5(1,1,1,1,0) - & ds5plus(1,1,1,1,0) , 0 ); - ASSERT_EQ( & ds5(1,1,1,1,0,0) - & ds5plus(1,1,1,1,0,0) , 0 ); // passing argument to rank beyond the view's rank is allowed iff it is a 0. + ASSERT_EQ(d5.rank(), 5); + + // LayoutStride arranged as LayoutRight - commented out as example that + // fails unit test + // unsigned order5[] = { 4,3,2,1,0 }, dimen5[] = { N0, N1, N2, 2, 2 }; + // sdView d5( "d5" , Kokkos::LayoutStride::order_dimensions(5, order5, + // dimen5) ); + // + // Fails the following unit test: + // ASSERT_EQ( d5.rank() , dr5.rank() ); + // + // Explanation: In construction of the Kokkos::LayoutStride below, since + // the + // remaining dimensions are not specified, they will default to values of + // 0 rather thanKOKKOS_INVALID_INDEX. + // When passed to the DynRankView constructor the default dimensions (of 0) + // will be counted toward the dynamic rank and returning an incorrect + // value (i.e. rank 7 rather than 5). + + // Check LayoutRight dr5 and LayoutStride d5 dimensions agree (as they + // should) + ASSERT_EQ(d5.extent(0), dr5.extent(0)); + ASSERT_EQ(d5.extent(1), dr5.extent(1)); + ASSERT_EQ(d5.extent(2), dr5.extent(2)); + ASSERT_EQ(d5.extent(3), dr5.extent(3)); + ASSERT_EQ(d5.extent(4), dr5.extent(4)); + ASSERT_EQ(d5.extent(5), dr5.extent(5)); + ASSERT_EQ(d5.rank(), dr5.rank()); + + // Rank 5 subview of rank 5 dynamic rank view, layout stride input + sdView ds5 = Kokkos::subdynrankview(d5, Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), + Kokkos::pair(0, 1)); + ASSERT_EQ(ds5.rank(), 5); + + // Pass in extra ALL arguments beyond the rank of the DynRank View. + // This behavior is allowed - ignore the extra ALL arguments when + // the src.rank() < number of arguments, but be careful! + sdView ds5plus = Kokkos::subdynrankview( + d5, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::pair(0, 1), Kokkos::ALL()); + + ASSERT_EQ(ds5.rank(), ds5plus.rank()); + ASSERT_EQ(ds5.extent(0), ds5plus.extent(0)); + ASSERT_EQ(ds5.extent(4), ds5plus.extent(4)); + ASSERT_EQ(ds5.extent(5), ds5plus.extent(5)); + +#if !defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_CUDA_UVM) + ASSERT_EQ(&ds5(1, 1, 1, 1, 0) - &ds5plus(1, 1, 1, 1, 0), 0); + ASSERT_EQ(&ds5(1, 1, 1, 1, 0, 0) - &ds5plus(1, 1, 1, 1, 0, 0), + 0); // passing argument to rank beyond the view's rank is allowed + // iff it is a 0. #endif -// Similar test to rank 5 above, but create rank 4 subview -// Check that the rank contracts (ds4 and ds4plus) and that subdynrankview can accept extra args (ds4plus) - sdView ds4 = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , 0 ); - sdView ds4plus = Kokkos::subdynrankview( d5 , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , Kokkos::ALL() , 0 , Kokkos::ALL() ); - - ASSERT_EQ( ds4.rank() , ds4plus.rank() ); - ASSERT_EQ( ds4.rank() , 4 ); - ASSERT_EQ( ds4.extent(0) , ds4plus.extent(0) ); - ASSERT_EQ( ds4.extent(4) , ds4plus.extent(4) ); - ASSERT_EQ( ds4.extent(5) , ds4plus.extent(5) ); + // Similar test to rank 5 above, but create rank 4 subview + // Check that the rank contracts (ds4 and ds4plus) and that subdynrankview + // can accept extra args (ds4plus) + sdView ds4 = Kokkos::subdynrankview(d5, Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), Kokkos::ALL(), 0); + sdView ds4plus = + Kokkos::subdynrankview(d5, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), + Kokkos::ALL(), 0, Kokkos::ALL()); + + ASSERT_EQ(ds4.rank(), ds4plus.rank()); + ASSERT_EQ(ds4.rank(), 4); + ASSERT_EQ(ds4.extent(0), ds4plus.extent(0)); + ASSERT_EQ(ds4.extent(4), ds4plus.extent(4)); + ASSERT_EQ(ds4.extent(5), ds4plus.extent(5)); } - static void run_test_subview_strided() - { - typedef Kokkos::DynRankView < int , Kokkos::LayoutLeft , host_drv_space > drview_left ; - typedef Kokkos::DynRankView < int , Kokkos::LayoutRight , host_drv_space > drview_right ; - typedef Kokkos::DynRankView < int , Kokkos::LayoutStride , host_drv_space > drview_stride ; - - drview_left xl2( "xl2", 100 , 200 ); - drview_right xr2( "xr2", 100 , 200 ); - drview_stride yl1 = Kokkos::subdynrankview( xl2 , 0 , Kokkos::ALL() ); - drview_stride yl2 = Kokkos::subdynrankview( xl2 , 1 , Kokkos::ALL() ); - drview_stride ys1 = Kokkos::subdynrankview( xr2 , 0 , Kokkos::ALL() ); - drview_stride ys2 = Kokkos::subdynrankview( xr2 , 1 , Kokkos::ALL() ); - drview_stride yr1 = Kokkos::subdynrankview( xr2 , 0 , Kokkos::ALL() ); - drview_stride yr2 = Kokkos::subdynrankview( xr2 , 1 , Kokkos::ALL() ); - - ASSERT_EQ( yl1.extent(0) , xl2.extent(1) ); - ASSERT_EQ( yl2.extent(0) , xl2.extent(1) ); - - ASSERT_EQ( yr1.extent(0) , xr2.extent(1) ); - ASSERT_EQ( yr2.extent(0) , xr2.extent(1) ); - - ASSERT_EQ( & yl1(0) - & xl2(0,0) , 0 ); - ASSERT_EQ( & yl2(0) - & xl2(1,0) , 0 ); - ASSERT_EQ( & yr1(0) - & xr2(0,0) , 0 ); - ASSERT_EQ( & yr2(0) - & xr2(1,0) , 0 ); - - - drview_left xl4( "xl4", 10 , 20 , 30 , 40 ); - drview_right xr4( "xr4", 10 , 20 , 30 , 40 ); - - //Replace subdynrankview with subview - test - drview_stride yl4 = Kokkos::subview( xl4 , 1 , Kokkos::ALL() , 2 , Kokkos::ALL() ); - drview_stride yr4 = Kokkos::subview( xr4 , 1 , Kokkos::ALL() , 2 , Kokkos::ALL() ); - - ASSERT_EQ( yl4.extent(0) , xl4.extent(1) ); - ASSERT_EQ( yl4.extent(1) , xl4.extent(3) ); - ASSERT_EQ( yr4.extent(0) , xr4.extent(1) ); - ASSERT_EQ( yr4.extent(1) , xr4.extent(3) ); - ASSERT_EQ( yl4.rank() , 2); - ASSERT_EQ( yr4.rank() , 2); - - ASSERT_EQ( & yl4(4,4) - & xl4(1,4,2,4) , 0 ); - ASSERT_EQ( & yr4(4,4) - & xr4(1,4,2,4) , 0 ); + static void run_test_subview_strided() { + typedef Kokkos::DynRankView + drview_left; + typedef Kokkos::DynRankView + drview_right; + typedef Kokkos::DynRankView + drview_stride; + + drview_left xl2("xl2", 100, 200); + drview_right xr2("xr2", 100, 200); + drview_stride yl1 = Kokkos::subdynrankview(xl2, 0, Kokkos::ALL()); + drview_stride yl2 = Kokkos::subdynrankview(xl2, 1, Kokkos::ALL()); + drview_stride ys1 = Kokkos::subdynrankview(xr2, 0, Kokkos::ALL()); + drview_stride ys2 = Kokkos::subdynrankview(xr2, 1, Kokkos::ALL()); + drview_stride yr1 = Kokkos::subdynrankview(xr2, 0, Kokkos::ALL()); + drview_stride yr2 = Kokkos::subdynrankview(xr2, 1, Kokkos::ALL()); + + ASSERT_EQ(yl1.extent(0), xl2.extent(1)); + ASSERT_EQ(yl2.extent(0), xl2.extent(1)); + + ASSERT_EQ(yr1.extent(0), xr2.extent(1)); + ASSERT_EQ(yr2.extent(0), xr2.extent(1)); + + ASSERT_EQ(&yl1(0) - &xl2(0, 0), 0); + ASSERT_EQ(&yl2(0) - &xl2(1, 0), 0); + ASSERT_EQ(&yr1(0) - &xr2(0, 0), 0); + ASSERT_EQ(&yr2(0) - &xr2(1, 0), 0); + + drview_left xl4("xl4", 10, 20, 30, 40); + drview_right xr4("xr4", 10, 20, 30, 40); + + // Replace subdynrankview with subview - test + drview_stride yl4 = + Kokkos::subview(xl4, 1, Kokkos::ALL(), 2, Kokkos::ALL()); + drview_stride yr4 = + Kokkos::subview(xr4, 1, Kokkos::ALL(), 2, Kokkos::ALL()); + + ASSERT_EQ(yl4.extent(0), xl4.extent(1)); + ASSERT_EQ(yl4.extent(1), xl4.extent(3)); + ASSERT_EQ(yr4.extent(0), xr4.extent(1)); + ASSERT_EQ(yr4.extent(1), xr4.extent(3)); + ASSERT_EQ(yl4.rank(), 2); + ASSERT_EQ(yr4.rank(), 2); + + ASSERT_EQ(&yl4(4, 4) - &xl4(1, 4, 2, 4), 0); + ASSERT_EQ(&yr4(4, 4) - &xr4(1, 4, 2, 4), 0); } - static void run_test_vector() - { - static const unsigned Length = 1000 , Count = 8 ; - - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutLeft , host_drv_space > multivector_type ; - - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutRight , host_drv_space > multivector_right_type ; - - multivector_type mv = multivector_type( "mv" , Length , Count ); - multivector_right_type mv_right = multivector_right_type( "mv" , Length , Count ); - - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutStride , host_drv_space > svector_type ; - typedef typename Kokkos::DynRankView< T , Kokkos::LayoutStride , host_drv_space > smultivector_type ; - typedef typename Kokkos::DynRankView< const T , Kokkos::LayoutStride , host_drv_space > const_svector_right_type ; - typedef typename Kokkos::DynRankView< const T , Kokkos::LayoutStride , host_drv_space > const_svector_type ; - typedef typename Kokkos::DynRankView< const T , Kokkos::LayoutStride , host_drv_space > const_smultivector_type ; - - svector_type v1 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 0 ); - svector_type v2 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 1 ); - svector_type v3 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 2 ); - - svector_type rv1 = Kokkos::subdynrankview( mv_right , 0 , Kokkos::ALL() ); - svector_type rv2 = Kokkos::subdynrankview( mv_right , 1 , Kokkos::ALL() ); - svector_type rv3 = Kokkos::subdynrankview( mv_right , 2 , Kokkos::ALL() ); - - smultivector_type mv1 = Kokkos::subdynrankview( mv , std::make_pair( 1 , 998 ) , - std::make_pair( 2 , 5 ) ); - - smultivector_type mvr1 = - Kokkos::subdynrankview( mv_right , - std::make_pair( 1 , 998 ) , - std::make_pair( 2 , 5 ) ); - - const_svector_type cv1 = Kokkos::subdynrankview( mv , Kokkos::ALL(), 0 ); - const_svector_type cv2 = Kokkos::subdynrankview( mv , Kokkos::ALL(), 1 ); - const_svector_type cv3 = Kokkos::subdynrankview( mv , Kokkos::ALL(), 2 ); - - svector_type vr1 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 0 ); - svector_type vr2 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 1 ); - svector_type vr3 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 2 ); - - const_svector_right_type cvr1 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 0 ); - const_svector_right_type cvr2 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 1 ); - const_svector_right_type cvr3 = Kokkos::subdynrankview( mv , Kokkos::ALL() , 2 ); - - - ASSERT_TRUE( & v1[0] == & v1(0) ); - ASSERT_TRUE( & v1[0] == & mv(0,0) ); - ASSERT_TRUE( & v2[0] == & mv(0,1) ); - ASSERT_TRUE( & v3[0] == & mv(0,2) ); - - ASSERT_TRUE( & cv1[0] == & mv(0,0) ); - ASSERT_TRUE( & cv2[0] == & mv(0,1) ); - ASSERT_TRUE( & cv3[0] == & mv(0,2) ); - - ASSERT_TRUE( & vr1[0] == & mv(0,0) ); - ASSERT_TRUE( & vr2[0] == & mv(0,1) ); - ASSERT_TRUE( & vr3[0] == & mv(0,2) ); - - ASSERT_TRUE( & cvr1[0] == & mv(0,0) ); - ASSERT_TRUE( & cvr2[0] == & mv(0,1) ); - ASSERT_TRUE( & cvr3[0] == & mv(0,2) ); - - - ASSERT_TRUE( & mv1(0,0) == & mv( 1 , 2 ) ); - ASSERT_TRUE( & mv1(1,1) == & mv( 2 , 3 ) ); - ASSERT_TRUE( & mv1(3,2) == & mv( 4 , 4 ) ); - ASSERT_TRUE( & mvr1(0,0) == & mv_right( 1 , 2 ) ); - ASSERT_TRUE( & mvr1(1,1) == & mv_right( 2 , 3 ) ); - ASSERT_TRUE( & mvr1(3,2) == & mv_right( 4 , 4 ) ); - - const_svector_type c_cv1( v1 ); - typename svector_type::const_type c_cv2( v2 ); - typename const_svector_type::const_type c_ccv2( v2 ); - - - const_smultivector_type cmv( mv ); - typename smultivector_type::const_type cmvX( cmv ); - typename const_smultivector_type::const_type ccmvX( cmv ); + static void run_test_vector() { + static const unsigned Length = 1000, Count = 8; + + typedef typename Kokkos::DynRankView + multivector_type; + + typedef typename Kokkos::DynRankView + multivector_right_type; + + multivector_type mv = multivector_type("mv", Length, Count); + multivector_right_type mv_right = + multivector_right_type("mv", Length, Count); + + typedef + typename Kokkos::DynRankView + svector_type; + typedef + typename Kokkos::DynRankView + smultivector_type; + typedef typename Kokkos::DynRankView + const_svector_right_type; + typedef typename Kokkos::DynRankView + const_svector_type; + typedef typename Kokkos::DynRankView + const_smultivector_type; + + svector_type v1 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + svector_type v2 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + svector_type v3 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + svector_type rv1 = Kokkos::subdynrankview(mv_right, 0, Kokkos::ALL()); + svector_type rv2 = Kokkos::subdynrankview(mv_right, 1, Kokkos::ALL()); + svector_type rv3 = Kokkos::subdynrankview(mv_right, 2, Kokkos::ALL()); + + smultivector_type mv1 = Kokkos::subdynrankview(mv, std::make_pair(1, 998), + std::make_pair(2, 5)); + + smultivector_type mvr1 = Kokkos::subdynrankview( + mv_right, std::make_pair(1, 998), std::make_pair(2, 5)); + + const_svector_type cv1 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + const_svector_type cv2 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + const_svector_type cv3 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + svector_type vr1 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + svector_type vr2 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + svector_type vr3 = Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + const_svector_right_type cvr1 = + Kokkos::subdynrankview(mv, Kokkos::ALL(), 0); + const_svector_right_type cvr2 = + Kokkos::subdynrankview(mv, Kokkos::ALL(), 1); + const_svector_right_type cvr3 = + Kokkos::subdynrankview(mv, Kokkos::ALL(), 2); + + ASSERT_TRUE(&v1[0] == &v1(0)); + ASSERT_TRUE(&v1[0] == &mv(0, 0)); + ASSERT_TRUE(&v2[0] == &mv(0, 1)); + ASSERT_TRUE(&v3[0] == &mv(0, 2)); + + ASSERT_TRUE(&cv1[0] == &mv(0, 0)); + ASSERT_TRUE(&cv2[0] == &mv(0, 1)); + ASSERT_TRUE(&cv3[0] == &mv(0, 2)); + + ASSERT_TRUE(&vr1[0] == &mv(0, 0)); + ASSERT_TRUE(&vr2[0] == &mv(0, 1)); + ASSERT_TRUE(&vr3[0] == &mv(0, 2)); + + ASSERT_TRUE(&cvr1[0] == &mv(0, 0)); + ASSERT_TRUE(&cvr2[0] == &mv(0, 1)); + ASSERT_TRUE(&cvr3[0] == &mv(0, 2)); + + ASSERT_TRUE(&mv1(0, 0) == &mv(1, 2)); + ASSERT_TRUE(&mv1(1, 1) == &mv(2, 3)); + ASSERT_TRUE(&mv1(3, 2) == &mv(4, 4)); + ASSERT_TRUE(&mvr1(0, 0) == &mv_right(1, 2)); + ASSERT_TRUE(&mvr1(1, 1) == &mv_right(2, 3)); + ASSERT_TRUE(&mvr1(3, 2) == &mv_right(4, 4)); + + const_svector_type c_cv1(v1); + typename svector_type::const_type c_cv2(v2); + typename const_svector_type::const_type c_ccv2(v2); + + const_smultivector_type cmv(mv); + typename smultivector_type::const_type cmvX(cmv); + typename const_smultivector_type::const_type ccmvX(cmv); } }; -} // namespace Test +} // namespace Test /*--------------------------------------------------------------------------*/ - diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp index 2909e8cc76..90ca5df194 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI_generic.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,9 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( TEST_CATEGORY , dyn_rank_view_api_generic) { - TestDynViewAPI< double , TEST_EXECSPACE >::run_tests(); +TEST(TEST_CATEGORY, dyn_rank_view_api_generic) { + TestDynViewAPI::run_tests(); } -} - +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp index 5b2c22440d..050ebbe35c 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank12345.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,11 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( TEST_CATEGORY , dyn_rank_view_api_operator_rank12345) { - TestDynViewAPI< double , TEST_EXECSPACE >::run_operator_test_rank12345(); +TEST(TEST_CATEGORY, dyn_rank_view_api_operator_rank12345) { + TestDynViewAPI::run_operator_test_rank12345(); } -} - +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp index 45a49fb819..eb8df60a89 100644 --- a/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynViewAPI_rank67.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,9 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( TEST_CATEGORY , dyn_rank_view_api_operator_rank67) { - TestDynViewAPI< double , TEST_EXECSPACE >::run_operator_test_rank67(); +TEST(TEST_CATEGORY, dyn_rank_view_api_operator_rank67) { + TestDynViewAPI::run_operator_test_rank67(); } -} - +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestDynamicView.hpp b/lib/kokkos/containers/unit_tests/TestDynamicView.hpp index 9e87fdf5cc..235464ef07 100644 --- a/lib/kokkos/containers/unit_tests/TestDynamicView.hpp +++ b/lib/kokkos/containers/unit_tests/TestDynamicView.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -55,45 +56,43 @@ namespace Test { -template< typename Scalar , class Space > -struct TestDynamicView -{ - typedef typename Space::execution_space execution_space ; - typedef typename Space::memory_space memory_space ; +template +struct TestDynamicView { + typedef typename Space::execution_space execution_space; + typedef typename Space::memory_space memory_space; - typedef Kokkos::Experimental::DynamicView view_type; + typedef Kokkos::Experimental::DynamicView view_type; typedef double value_type; - static void run( unsigned arg_total_size ) - { - // Test: Create DynamicView, initialize size (via resize), run through parallel_for to set values, check values (via parallel_reduce); resize values and repeat + static void run(unsigned arg_total_size) { + // Test: Create DynamicView, initialize size (via resize), run through + // parallel_for to set values, check values (via parallel_reduce); resize + // values and repeat // Case 1: min_chunk_size is a power of 2 { - view_type da("da", 1024, arg_total_size ); - ASSERT_EQ( da.size(), 0 ); + view_type da("da", 1024, arg_total_size); + ASSERT_EQ(da.size(), 0); // Init unsigned da_size = arg_total_size / 8; da.resize_serial(da_size); - ASSERT_EQ( da.size(), da_size ); + ASSERT_EQ(da.size(), da_size); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , result_sum - ); - - ASSERT_EQ(result_sum, (value_type)( da_size * (da_size - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + result_sum); + + ASSERT_EQ(result_sum, (value_type)(da_size * (da_size - 1) / 2)); #endif #endif @@ -101,56 +100,55 @@ struct TestDynamicView // the first 1/4 should remain the same unsigned da_resize = arg_total_size / 2; da.resize_serial(da_resize); - ASSERT_EQ( da.size(), da_resize ); + ASSERT_EQ(da.size(), da_resize); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type new_result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , new_result_sum - ); - - ASSERT_EQ(new_result_sum+result_sum, (value_type)( da_resize * (da_resize - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + new_result_sum); + + ASSERT_EQ(new_result_sum + result_sum, + (value_type)(da_resize * (da_resize - 1) / 2)); #endif #endif - } // end scope + } // end scope - // Test: Create DynamicView, initialize size (via resize), run through parallel_for to set values, check values (via parallel_reduce); resize values and repeat + // Test: Create DynamicView, initialize size (via resize), run through + // parallel_for to set values, check values (via parallel_reduce); resize + // values and repeat // Case 2: min_chunk_size is NOT a power of 2 { - view_type da("da", 1023, arg_total_size ); - ASSERT_EQ( da.size(), 0 ); + view_type da("da", 1023, arg_total_size); + ASSERT_EQ(da.size(), 0); // Init unsigned da_size = arg_total_size / 8; da.resize_serial(da_size); - ASSERT_EQ( da.size(), da_size ); + ASSERT_EQ(da.size(), da_size); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , result_sum - ); - - ASSERT_EQ(result_sum, (value_type)( da_size * (da_size - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + result_sum); + + ASSERT_EQ(result_sum, (value_type)(da_size * (da_size - 1) / 2)); #endif #endif @@ -158,99 +156,92 @@ struct TestDynamicView // the first 1/4 should remain the same unsigned da_resize = arg_total_size / 2; da.resize_serial(da_resize); - ASSERT_EQ( da.size(), da_resize ); + ASSERT_EQ(da.size(), da_resize); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type new_result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(da_size, da_resize), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , new_result_sum - ); - - ASSERT_EQ(new_result_sum+result_sum, (value_type)( da_resize * (da_resize - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(da_size, da_resize), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + new_result_sum); + + ASSERT_EQ(new_result_sum + result_sum, + (value_type)(da_resize * (da_resize - 1) / 2)); #endif #endif - } // end scope + } // end scope - // Test: Create DynamicView, initialize size (via resize), run through parallel_for to set values, check values (via parallel_reduce); resize values and repeat + // Test: Create DynamicView, initialize size (via resize), run through + // parallel_for to set values, check values (via parallel_reduce); resize + // values and repeat // Case 3: resize reduces the size { - view_type da("da", 1023, arg_total_size ); - ASSERT_EQ( da.size(), 0 ); + view_type da("da", 1023, arg_total_size); + ASSERT_EQ(da.size(), 0); // Init unsigned da_size = arg_total_size / 2; da.resize_serial(da_size); - ASSERT_EQ( da.size(), da_size ); + ASSERT_EQ(da.size(), da_size); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_size), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , result_sum - ); - - ASSERT_EQ(result_sum, (value_type)( da_size * (da_size - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_size), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + result_sum); + + ASSERT_EQ(result_sum, (value_type)(da_size * (da_size - 1) / 2)); #endif #endif // remove the final 3/4 entries i.e. first 1/4 remain unsigned da_resize = arg_total_size / 8; da.resize_serial(da_resize); - ASSERT_EQ( da.size(), da_resize ); + ASSERT_EQ(da.size(), da_resize); -#if defined( KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA ) -#if !defined(KOKKOS_ENABLE_CUDA) || ( 8000 <= CUDA_VERSION ) - Kokkos::parallel_for( Kokkos::RangePolicy(0, da_resize), KOKKOS_LAMBDA ( const int i ) - { - da(i) = Scalar(i); - } - ); +#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA) +#if !defined(KOKKOS_ENABLE_CUDA) || (8000 <= CUDA_VERSION) + Kokkos::parallel_for( + Kokkos::RangePolicy(0, da_resize), + KOKKOS_LAMBDA(const int i) { da(i) = Scalar(i); }); value_type new_result_sum = 0.0; - Kokkos::parallel_reduce( Kokkos::RangePolicy(0, da_resize), KOKKOS_LAMBDA ( const int i, value_type& partial_sum ) - { - partial_sum += (value_type)da(i); - } - , new_result_sum - ); - - ASSERT_EQ(new_result_sum, (value_type)( da_resize * (da_resize - 1) / 2 ) ); + Kokkos::parallel_reduce( + Kokkos::RangePolicy(0, da_resize), + KOKKOS_LAMBDA(const int i, value_type& partial_sum) { + partial_sum += (value_type)da(i); + }, + new_result_sum); + + ASSERT_EQ(new_result_sum, (value_type)(da_resize * (da_resize - 1) / 2)); #endif #endif - } // end scope - + } // end scope } }; -TEST_F( TEST_CATEGORY , dynamic_view ) -{ - typedef TestDynamicView< double , TEST_EXECSPACE > - TestDynView ; +TEST(TEST_CATEGORY, dynamic_view) { + typedef TestDynamicView TestDynView; - for ( int i = 0 ; i < 10 ; ++i ) { - TestDynView::run( 100000 + 100 * i ); + for (int i = 0; i < 10; ++i) { + TestDynView::run(100000 + 100 * i); } } -} // namespace Test +} // namespace Test #endif /* #ifndef KOKKOS_TEST_DYNAMICVIEW_HPP */ - diff --git a/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp b/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp index 7e48089b43..49b71cdea7 100644 --- a/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp +++ b/lib/kokkos/containers/unit_tests/TestErrorReporter.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,47 +52,47 @@ namespace Test { -// Just save the data in the report. Informative text goies in the operator<<(..). +// Just save the data in the report. Informative text goies in the +// operator<<(..). template -struct ThreeValReport -{ +struct ThreeValReport { DataType1 m_data1; DataType2 m_data2; DataType3 m_data3; - }; template -std::ostream &operator<<(std::ostream & os, const ThreeValReport &val) -{ - return os << "{" << val.m_data1 << " " << val.m_data2 << " " << val.m_data3 << "}"; +std::ostream &operator<<( + std::ostream &os, + const ThreeValReport &val) { + return os << "{" << val.m_data1 << " " << val.m_data2 << " " << val.m_data3 + << "}"; } -template +template void checkReportersAndReportsAgree(const std::vector &reporters, - const std::vector &reports) -{ + const std::vector &reports) { for (size_t i = 0; i < reports.size(); ++i) { EXPECT_EQ(1, reporters[i] % 2); EXPECT_EQ(reporters[i], reports[i].m_data1); } } - template struct ErrorReporterDriverBase { - - typedef ThreeValReport report_type; - typedef Kokkos::Experimental::ErrorReporter error_reporter_type; + typedef ThreeValReport report_type; + typedef Kokkos::Experimental::ErrorReporter + error_reporter_type; error_reporter_type m_errorReporter; ErrorReporterDriverBase(int reporter_capacity, int test_size) - : m_errorReporter(reporter_capacity) { } + : m_errorReporter(reporter_capacity) {} - KOKKOS_INLINE_FUNCTION bool error_condition(const int work_idx) const { return (work_idx % 2 != 0); } + KOKKOS_INLINE_FUNCTION bool error_condition(const int work_idx) const { + return (work_idx % 2 != 0); + } - void check_expectations(int reporter_capacity, int test_size) - { + void check_expectations(int reporter_capacity, int test_size) { int num_reported = m_errorReporter.getNumReports(); int num_attempts = m_errorReporter.getNumReportAttempts(); @@ -99,15 +100,14 @@ struct ErrorReporterDriverBase { EXPECT_EQ(expected_num_reports, num_reported); EXPECT_EQ(test_size / 2, num_attempts); - bool expect_full = (reporter_capacity <= (test_size / 2)); + bool expect_full = (reporter_capacity <= (test_size / 2)); bool reported_full = m_errorReporter.full(); EXPECT_EQ(expect_full, reported_full); } }; template -void TestErrorReporter() -{ +void TestErrorReporter() { typedef ErrorReporterDriverType tester_type; std::vector reporters; std::vector reports; @@ -120,9 +120,12 @@ void TestErrorReporter() test2.m_errorReporter.getReports(reporters, reports); checkReportersAndReportsAgree(reporters, reports); - typename Kokkos::View::HostMirror view_reporters; - typename Kokkos::View::HostMirror - view_reports; + typename Kokkos::View< + int *, typename ErrorReporterDriverType::execution_space>::HostMirror + view_reporters; + typename Kokkos::View:: + HostMirror view_reports; test2.m_errorReporter.getReports(view_reporters, view_reports); int num_reports = view_reporters.extent(0); @@ -136,19 +139,16 @@ void TestErrorReporter() reports.push_back(view_reports(i)); } checkReportersAndReportsAgree(reporters, reports); - } - template -struct ErrorReporterDriver : public ErrorReporterDriverBase -{ - typedef ErrorReporterDriverBase driver_base; - typedef typename driver_base::error_reporter_type::execution_space execution_space; +struct ErrorReporterDriver : public ErrorReporterDriverBase { + typedef ErrorReporterDriverBase driver_base; + typedef typename driver_base::error_reporter_type::execution_space + execution_space; ErrorReporterDriver(int reporter_capacity, int test_size) - : driver_base(reporter_capacity, test_size) - { + : driver_base(reporter_capacity, test_size) { execute(reporter_capacity, test_size); // Test that clear() and resize() work across memory spaces. @@ -159,19 +159,18 @@ struct ErrorReporterDriver : public ErrorReporterDriverBase } } - void execute(int reporter_capacity, int test_size) - { - Kokkos::parallel_for(Kokkos::RangePolicy(0,test_size), *this); + void execute(int reporter_capacity, int test_size) { + Kokkos::parallel_for(Kokkos::RangePolicy(0, test_size), + *this); Kokkos::fence(); driver_base::check_expectations(reporter_capacity, test_size); } KOKKOS_INLINE_FUNCTION - void operator()(const int work_idx) const - { + void operator()(const int work_idx) const { if (driver_base::error_condition(work_idx)) { double val = M_PI * static_cast(work_idx); - typename driver_base::report_type report = {work_idx, -2*work_idx, val}; + typename driver_base::report_type report = {work_idx, -2 * work_idx, val}; driver_base::m_errorReporter.add_report(work_idx, report); } } @@ -179,45 +178,45 @@ struct ErrorReporterDriver : public ErrorReporterDriverBase #if defined(KOKKOS_CLASS_LAMBDA) template -struct ErrorReporterDriverUseLambda : public ErrorReporterDriverBase -{ - - typedef ErrorReporterDriverBase driver_base; - typedef typename driver_base::error_reporter_type::execution_space execution_space; +struct ErrorReporterDriverUseLambda + : public ErrorReporterDriverBase { + typedef ErrorReporterDriverBase driver_base; + typedef typename driver_base::error_reporter_type::execution_space + execution_space; ErrorReporterDriverUseLambda(int reporter_capacity, int test_size) - : driver_base(reporter_capacity, test_size) - { - Kokkos::parallel_for(Kokkos::RangePolicy(0,test_size), KOKKOS_CLASS_LAMBDA (const int work_idx) { - if (driver_base::error_condition(work_idx)) { - double val = M_PI * static_cast(work_idx); - typename driver_base::report_type report = {work_idx, -2*work_idx, val}; - driver_base::m_errorReporter.add_report(work_idx, report); - } - }); + : driver_base(reporter_capacity, test_size) { + Kokkos::parallel_for( + Kokkos::RangePolicy(0, test_size), + KOKKOS_CLASS_LAMBDA(const int work_idx) { + if (driver_base::error_condition(work_idx)) { + double val = M_PI * static_cast(work_idx); + typename driver_base::report_type report = {work_idx, -2 * work_idx, + val}; + driver_base::m_errorReporter.add_report(work_idx, report); + } + }); Kokkos::fence(); driver_base::check_expectations(reporter_capacity, test_size); } - }; #endif - #ifdef KOKKOS_ENABLE_OPENMP -struct ErrorReporterDriverNativeOpenMP : public ErrorReporterDriverBase -{ - typedef ErrorReporterDriverBase driver_base; - typedef typename driver_base::error_reporter_type::execution_space execution_space; +struct ErrorReporterDriverNativeOpenMP + : public ErrorReporterDriverBase { + typedef ErrorReporterDriverBase driver_base; + typedef typename driver_base::error_reporter_type::execution_space + execution_space; ErrorReporterDriverNativeOpenMP(int reporter_capacity, int test_size) - : driver_base(reporter_capacity, test_size) - { + : driver_base(reporter_capacity, test_size) { #pragma omp parallel for - for(int work_idx = 0; work_idx < test_size; ++work_idx) - { + for (int work_idx = 0; work_idx < test_size; ++work_idx) { if (driver_base::error_condition(work_idx)) { double val = M_PI * static_cast(work_idx); - typename driver_base::report_type report = {work_idx, -2*work_idx, val}; + typename driver_base::report_type report = {work_idx, -2 * work_idx, + val}; driver_base::m_errorReporter.add_report(work_idx, report); } }; @@ -227,17 +226,14 @@ struct ErrorReporterDriverNativeOpenMP : public ErrorReporterDriverBase>(); } #endif -TEST_F(TEST_CATEGORY, ErrorReporter) -{ +TEST(TEST_CATEGORY, ErrorReporter) { TestErrorReporter>(); } -} // namespace Test -#endif // #ifndef KOKKOS_TEST_ERROR_REPORTING_HPP - +} // namespace Test +#endif // #ifndef KOKKOS_TEST_ERROR_REPORTING_HPP diff --git a/lib/kokkos/containers/unit_tests/TestOffsetView.hpp b/lib/kokkos/containers/unit_tests/TestOffsetView.hpp index 6965199d45..12bcda9524 100644 --- a/lib/kokkos/containers/unit_tests/TestOffsetView.hpp +++ b/lib/kokkos/containers/unit_tests/TestOffsetView.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,8 +46,6 @@ #ifndef CONTAINERS_UNIT_TESTS_TESTOFFSETVIEW_HPP_ #define CONTAINERS_UNIT_TESTS_TESTOFFSETVIEW_HPP_ - - #include #include #include @@ -55,372 +54,652 @@ #include #include -using std::endl; using std::cout; +using std::endl; -namespace Test{ - - template - void test_offsetview_construction(unsigned int size) - { - - typedef Kokkos::Experimental::OffsetView offset_view_type; - typedef Kokkos::View view_type; +namespace Test { - Kokkos::Experimental::index_list_type range0 = {-1, 3}; - Kokkos::Experimental::index_list_type range1 = {-2, 2}; +template +void test_offsetview_construction(unsigned int size) { + typedef Kokkos::Experimental::OffsetView offset_view_type; + typedef Kokkos::View view_type; - offset_view_type ov("firstOV", range0, range1); + Kokkos::Experimental::index_list_type range0 = {-1, 3}; + Kokkos::Experimental::index_list_type range1 = {-2, 2}; - ASSERT_EQ("firstOV", ov.label()); - ASSERT_EQ(2, ov.Rank); + offset_view_type ov("firstOV", range0, range1); - ASSERT_EQ(ov.begin(0), -1); - ASSERT_EQ(ov.end(0), 4); + ASSERT_EQ("firstOV", ov.label()); + ASSERT_EQ(2, ov.Rank); - ASSERT_EQ(ov.begin(1), -2); - ASSERT_EQ(ov.end(1), 3); + ASSERT_EQ(ov.begin(0), -1); + ASSERT_EQ(ov.end(0), 4); - ASSERT_EQ(ov.extent(0), 5); - ASSERT_EQ(ov.extent(1), 5); + ASSERT_EQ(ov.begin(1), -2); + ASSERT_EQ(ov.end(1), 3); - const int ovmin0 = ov.begin(0); - const int ovend0 = ov.end(0); - const int ovmin1 = ov.begin(1); - const int ovend1 = ov.end(1); + ASSERT_EQ(ov.extent(0), 5); + ASSERT_EQ(ov.extent(1), 5); #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - { - Kokkos::Experimental::OffsetView offsetV1("OneDOffsetView", range0); - - Kokkos::RangePolicy rangePolicy1(offsetV1.begin(0), offsetV1.end(0)); - Kokkos::parallel_for(rangePolicy1, KOKKOS_LAMBDA (const int i){ - offsetV1(i) = 1; - } - ); - Kokkos::fence(); - - int OVResult = 0; - Kokkos::parallel_reduce(rangePolicy1, KOKKOS_LAMBDA(const int i, int & updateMe){ - updateMe += offsetV1(i); - }, OVResult); - - Kokkos::fence(); - ASSERT_EQ(OVResult, offsetV1.end(0) - offsetV1.begin(0)) << "found wrong number of elements in OffsetView that was summed."; - - } - { //test deep copy of scalar const value into mirro - const int constVal = 6; - typename offset_view_type::HostMirror hostOffsetView = - Kokkos::Experimental::create_mirror_view(ov); - - Kokkos::Experimental::deep_copy(hostOffsetView, constVal); - - for(int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { - for(int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { - ASSERT_EQ(hostOffsetView(i,j), constVal) << "Bad data found in OffsetView"; - } - } - } - - typedef Kokkos::MDRangePolicy, Kokkos::IndexType > range_type; - typedef typename range_type::point_type point_type; - - range_type rangePolicy2D(point_type{ {ovmin0, ovmin1 } }, - point_type{ { ovend0, ovend1 } }); - - const int constValue = 9; - Kokkos::parallel_for(rangePolicy2D, KOKKOS_LAMBDA (const int i, const int j) { - ov(i,j) = constValue; - } - ); - - //test offsetview to offsetviewmirror deep copy - typename offset_view_type::HostMirror hostOffsetView = - Kokkos::Experimental::create_mirror_view(ov); - - Kokkos::Experimental::deep_copy(hostOffsetView, ov); - - for(int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { - for(int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { - ASSERT_EQ(hostOffsetView(i,j), constValue) << "Bad data found in OffsetView"; - } - } - - int OVResult = 0; - Kokkos::parallel_reduce(rangePolicy2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += ov(i, j); - }, OVResult); - - int answer = 0; - for(int i = ov.begin(0); i < ov.end(0); ++i) { - for(int j = ov.begin(1); j < ov.end(1); ++j) { - answer += constValue; - } + const int ovmin0 = ov.begin(0); + const int ovend0 = ov.end(0); + const int ovmin1 = ov.begin(1); + const int ovend1 = ov.end(1); + { + Kokkos::Experimental::OffsetView offsetV1("OneDOffsetView", + range0); + + Kokkos::RangePolicy rangePolicy1(offsetV1.begin(0), + offsetV1.end(0)); + Kokkos::parallel_for( + rangePolicy1, KOKKOS_LAMBDA(const int i) { offsetV1(i) = 1; }); + Kokkos::fence(); + + int OVResult = 0; + Kokkos::parallel_reduce( + rangePolicy1, + KOKKOS_LAMBDA(const int i, int& updateMe) { updateMe += offsetV1(i); }, + OVResult); + + Kokkos::fence(); + ASSERT_EQ(OVResult, offsetV1.end(0) - offsetV1.begin(0)) + << "found wrong number of elements in OffsetView that was summed."; + } + { // test deep copy of scalar const value into mirro + const int constVal = 6; + typename offset_view_type::HostMirror hostOffsetView = + Kokkos::Experimental::create_mirror_view(ov); + + Kokkos::Experimental::deep_copy(hostOffsetView, constVal); + + for (int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { + for (int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { + ASSERT_EQ(hostOffsetView(i, j), constVal) + << "Bad data found in OffsetView"; } - - ASSERT_EQ(OVResult, answer) << "Bad data found in OffsetView"; + } + } + + typedef Kokkos::MDRangePolicy, + Kokkos::IndexType > + range_type; + typedef typename range_type::point_type point_type; + + range_type rangePolicy2D(point_type{{ovmin0, ovmin1}}, + point_type{{ovend0, ovend1}}); + + const int constValue = 9; + Kokkos::parallel_for( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j) { ov(i, j) = constValue; }); + + // test offsetview to offsetviewmirror deep copy + typename offset_view_type::HostMirror hostOffsetView = + Kokkos::Experimental::create_mirror_view(ov); + + Kokkos::Experimental::deep_copy(hostOffsetView, ov); + + for (int i = hostOffsetView.begin(0); i < hostOffsetView.end(0); ++i) { + for (int j = hostOffsetView.begin(1); j < hostOffsetView.end(1); ++j) { + ASSERT_EQ(hostOffsetView(i, j), constValue) + << "Bad data found in OffsetView"; + } + } + + int OVResult = 0; + Kokkos::parallel_reduce( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += ov(i, j); + }, + OVResult); + + int answer = 0; + for (int i = ov.begin(0); i < ov.end(0); ++i) { + for (int j = ov.begin(1); j < ov.end(1); ++j) { + answer += constValue; + } + } + + ASSERT_EQ(OVResult, answer) << "Bad data found in OffsetView"; #endif - { - offset_view_type ovCopy(ov); - ASSERT_EQ(ovCopy==ov, true) << - "Copy constructor or equivalence operator broken"; - } - - { - offset_view_type ovAssigned = ov; - ASSERT_EQ(ovAssigned==ov, true) << - "Assignment operator or equivalence operator broken"; - } - - { //construct OffsetView from a View plus begins array - const int extent0 = 100; - const int extent1 = 200; - const int extent2 = 300; - Kokkos::View view3D("view3D", extent0, extent1, extent2); - - Kokkos::deep_copy(view3D, 1); + { + offset_view_type ovCopy(ov); + ASSERT_EQ(ovCopy == ov, true) + << "Copy constructor or equivalence operator broken"; + } - Kokkos::Array begins = {{-10, -20, -30}}; - Kokkos::Experimental::OffsetView offsetView3D(view3D, begins); + { + offset_view_type ovAssigned = ov; + ASSERT_EQ(ovAssigned == ov, true) + << "Assignment operator or equivalence operator broken"; + } - typedef Kokkos::MDRangePolicy, Kokkos::IndexType > range3_type; - typedef typename range3_type::point_type point3_type; + { // construct OffsetView from a View plus begins array + const int extent0 = 100; + const int extent1 = 200; + const int extent2 = 300; + Kokkos::View view3D("view3D", extent0, extent1, extent2); - range3_type rangePolicy3DZero(point3_type{ {0, 0, 0 } }, - point3_type{ { extent0, extent1, extent2 } }); + Kokkos::deep_copy(view3D, 1); -#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - int view3DSum = 0; - Kokkos::parallel_reduce(rangePolicy3DZero, KOKKOS_LAMBDA(const int i, const int j, int k, int & updateMe){ - updateMe += view3D(i, j, k); - }, view3DSum); + Kokkos::Array begins = {{-10, -20, -30}}; + Kokkos::Experimental::OffsetView offsetView3D(view3D, + begins); - range3_type rangePolicy3D(point3_type{ {begins[0], begins[1], begins[2] } }, - point3_type{ { begins[0] + extent0, begins[1] + extent1, begins[2] + extent2 } }); - int offsetView3DSum = 0; + typedef Kokkos::MDRangePolicy, + Kokkos::IndexType > + range3_type; + typedef typename range3_type::point_type point3_type; - Kokkos::parallel_reduce(rangePolicy3D, KOKKOS_LAMBDA(const int i, const int j, int k, int & updateMe){ - updateMe += offsetView3D(i, j, k); - }, offsetView3DSum); + range3_type rangePolicy3DZero(point3_type{{0, 0, 0}}, + point3_type{{extent0, extent1, extent2}}); - ASSERT_EQ(view3DSum, offsetView3DSum) << "construction of OffsetView from View and begins array broken."; +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + int view3DSum = 0; + Kokkos::parallel_reduce( + rangePolicy3DZero, + KOKKOS_LAMBDA(const int i, const int j, int k, int& updateMe) { + updateMe += view3D(i, j, k); + }, + view3DSum); + + range3_type rangePolicy3D( + point3_type{{begins[0], begins[1], begins[2]}}, + point3_type{ + {begins[0] + extent0, begins[1] + extent1, begins[2] + extent2}}); + int offsetView3DSum = 0; + + Kokkos::parallel_reduce( + rangePolicy3D, + KOKKOS_LAMBDA(const int i, const int j, int k, int& updateMe) { + updateMe += offsetView3D(i, j, k); + }, + offsetView3DSum); + + ASSERT_EQ(view3DSum, offsetView3DSum) + << "construction of OffsetView from View and begins array broken."; #endif - } - view_type viewFromOV = ov.view(); - - ASSERT_EQ(viewFromOV == ov, true) << - "OffsetView::view() or equivalence operator View == OffsetView broken"; - - { - offset_view_type ovFromV(viewFromOV, {-1, -2}); - - ASSERT_EQ(ovFromV == viewFromOV , true) << - "Construction of OffsetView from View or equivalence operator OffsetView == View broken"; - } - { - offset_view_type ovFromV = viewFromOV; - ASSERT_EQ(ovFromV == viewFromOV , true) << - "Construction of OffsetView from View by assignment (implicit conversion) or equivalence operator OffsetView == View broken"; - } - - {// test offsetview to view deep copy - view_type aView("aView", ov.extent(0), ov.extent(1)); - Kokkos::Experimental::deep_copy(aView, ov); + } + view_type viewFromOV = ov.view(); + + ASSERT_EQ(viewFromOV == ov, true) + << "OffsetView::view() or equivalence operator View == OffsetView broken"; + + { + offset_view_type ovFromV(viewFromOV, {-1, -2}); + + ASSERT_EQ(ovFromV == viewFromOV, true) + << "Construction of OffsetView from View or equivalence operator " + "OffsetView == View broken"; + } + { + offset_view_type ovFromV = viewFromOV; + ASSERT_EQ(ovFromV == viewFromOV, true) + << "Construction of OffsetView from View by assignment (implicit " + "conversion) or equivalence operator OffsetView == View broken"; + } + + { // test offsetview to view deep copy + view_type aView("aView", ov.extent(0), ov.extent(1)); + Kokkos::Experimental::deep_copy(aView, ov); #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - int sum = 0; - Kokkos::parallel_reduce(rangePolicy2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += ov(i, j) - aView(i- ov.begin(0), j-ov.begin(1)); - }, sum); - - ASSERT_EQ(sum, 0) << "deep_copy(view, offsetView) broken."; + int sum = 0; + Kokkos::parallel_reduce( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += ov(i, j) - aView(i - ov.begin(0), j - ov.begin(1)); + }, + sum); + + ASSERT_EQ(sum, 0) << "deep_copy(view, offsetView) broken."; #endif - } + } - {// test view to offsetview deep copy - view_type aView("aView", ov.extent(0), ov.extent(1)); + { // test view to offsetview deep copy + view_type aView("aView", ov.extent(0), ov.extent(1)); - Kokkos::deep_copy(aView, 99); - Kokkos::Experimental::deep_copy(ov, aView); - + Kokkos::deep_copy(aView, 99); + Kokkos::Experimental::deep_copy(ov, aView); #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - int sum = 0; - Kokkos::parallel_reduce(rangePolicy2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += ov(i, j) - aView(i- ov.begin(0), j-ov.begin(1)); - }, sum); - - ASSERT_EQ(sum, 0) << "deep_copy(offsetView, view) broken."; + int sum = 0; + Kokkos::parallel_reduce( + rangePolicy2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += ov(i, j) - aView(i - ov.begin(0), j - ov.begin(1)); + }, + sum); + + ASSERT_EQ(sum, 0) << "deep_copy(offsetView, view) broken."; #endif - } - } - template - void test_offsetview_subview(unsigned int size) - { - {//test subview 1 - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10, 20}); - { - auto offsetSubviewa = Kokkos::Experimental::subview(sliceMe, 0); - ASSERT_EQ(offsetSubviewa.Rank, 0) << "subview of offset is broken."; - } - - } - {//test subview 2 - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10,20}, {-20,30}); - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(),-2); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - } + } +} + +template +void test_offsetview_unmanaged_construction() { + // Preallocated memory (Only need a valid address for this test) + Scalar s; + + { + // Constructing an OffsetView directly around our preallocated memory + Kokkos::Array begins1{{2}}; + Kokkos::Array ends1{{3}}; + Kokkos::Experimental::OffsetView ov1(&s, begins1, ends1); + + // Constructing an OffsetView around an unmanaged View of our preallocated + // memory + Kokkos::View v1(&s, ends1[0] - begins1[0]); + Kokkos::Experimental::OffsetView ovv1(v1, begins1); + + // They should match + ASSERT_EQ(ovv1, ov1) + << "OffsetView unmanaged construction fails for rank 1"; + } + + { + Kokkos::Array begins2{{-2, -7}}; + Kokkos::Array ends2{{5, -3}}; + Kokkos::Experimental::OffsetView ov2(&s, begins2, ends2); + + Kokkos::View v2(&s, ends2[0] - begins2[0], + ends2[1] - begins2[1]); + Kokkos::Experimental::OffsetView ovv2(v2, begins2); + + ASSERT_EQ(ovv2, ov2) + << "OffsetView unmanaged construction fails for rank 2"; + } + + { + Kokkos::Array begins3{{2, 3, 5}}; + Kokkos::Array ends3{{7, 11, 13}}; + Kokkos::Experimental::OffsetView ovv3(&s, begins3, + ends3); + + Kokkos::View v3(&s, ends3[0] - begins3[0], + ends3[1] - begins3[1], + ends3[2] - begins3[2]); + Kokkos::Experimental::OffsetView ov3(v3, begins3); + + ASSERT_EQ(ovv3, ov3) + << "OffsetView unmanaged construction fails for rank 3"; + } + + { + // Test all four public constructor overloads (begins_type x + // index_list_type) + Kokkos::Array begins{{-3}}; + Kokkos::Array ends{{2}}; + + Kokkos::Experimental::OffsetView bb(&s, begins, ends); + Kokkos::Experimental::OffsetView bi(&s, begins, {2}); + Kokkos::Experimental::OffsetView ib(&s, {-3}, ends); + Kokkos::Experimental::OffsetView ii(&s, {-3}, {2}); + + ASSERT_EQ(bb, bi); + ASSERT_EQ(bb, ib); + ASSERT_EQ(bb, ii); + } + +#ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST + { + using offset_view_type = Kokkos::Experimental::OffsetView; + + // Range calculations must be positive + ASSERT_NO_THROW(offset_view_type(&s, {0}, {1})); + ASSERT_NO_THROW(offset_view_type(&s, {0}, {0})); + ASSERT_THROW(offset_view_type(&s, {0}, {-1}), std::runtime_error); + } + + { + using offset_view_type = Kokkos::Experimental::OffsetView; + + // Range calculations must not overflow + ASSERT_NO_THROW(offset_view_type(&s, {0}, {0x7fffffffffffffffl})); + ASSERT_THROW(offset_view_type(&s, {-1}, {0x7fffffffffffffffl}), + std::runtime_error); + ASSERT_THROW( + offset_view_type(&s, {-0x7fffffffffffffffl - 1}, {0x7fffffffffffffffl}), + std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {-0x7fffffffffffffffl - 1}, {0}), + std::runtime_error); + } + + { + using offset_view_type = Kokkos::Experimental::OffsetView; + + // Should throw when the rank of begins and/or ends doesn't match that of + // OffsetView + ASSERT_THROW(offset_view_type(&s, {0}, {1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0}, {1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0}, {1, 1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0}, {1}), std::runtime_error); + ASSERT_NO_THROW(offset_view_type(&s, {0, 0}, {1, 1})); + ASSERT_THROW(offset_view_type(&s, {0, 0}, {1, 1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0, 0}, {1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0, 0}, {1, 1}), std::runtime_error); + ASSERT_THROW(offset_view_type(&s, {0, 0, 0}, {1, 1, 1}), + std::runtime_error); + } +#endif // KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST +} + +template +void test_offsetview_subview(unsigned int size) { + { // test subview 1 + Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", + {-10, 20}); + { + auto offsetSubviewa = Kokkos::Experimental::subview(sliceMe, 0); + ASSERT_EQ(offsetSubviewa.Rank, 0) << "subview of offset is broken."; + } + } + { // test subview 2 + Kokkos::Experimental::OffsetView sliceMe( + "offsetToSlice", {-10, 20}, {-20, 30}); + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), -2); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + } + + { // test subview rank 3 + + Kokkos::Experimental::OffsetView sliceMe( + "offsetToSlice", {-10, 20}, {-20, 30}, {-30, 40}); + + // slice 1 + { + auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), + Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), + 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + } + + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), Kokkos::make_pair(-30, -21)); + ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + + ASSERT_EQ(offsetSubview.begin(0), -20); + ASSERT_EQ(offsetSubview.end(0), 31); + ASSERT_EQ(offsetSubview.begin(1), 0); + ASSERT_EQ(offsetSubview.end(1), 9); +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + typedef Kokkos::MDRangePolicy, + Kokkos::IndexType > + range_type; + typedef typename range_type::point_type point_type; - {//test subview rank 3 + const int b0 = offsetSubview.begin(0); + const int b1 = offsetSubview.begin(1); - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10,20}, {-20,30}, {-30,40}); + const int e0 = offsetSubview.end(0); + const int e1 = offsetSubview.end(1); - //slice 1 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,Kokkos::ALL(),Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,Kokkos::ALL(), 0,Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; - } + range_type rangeP2D(point_type{{b0, b1}}, point_type{{e0, e1}}); - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,0, Kokkos::ALL(),Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + Kokkos::parallel_for( + rangeP2D, + KOKKOS_LAMBDA(const int i, const int j) { offsetSubview(i, j) = 6; }); - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe,0, Kokkos::ALL(), Kokkos::make_pair(-30, -21)); - ASSERT_EQ(offsetSubview.Rank, 2) << "subview of offset is broken."; + int sum = 0; + Kokkos::parallel_reduce( + rangeP2D, + KOKKOS_LAMBDA(const int i, const int j, int& updateMe) { + updateMe += offsetSubview(i, j); + }, + sum); - ASSERT_EQ(offsetSubview.begin(0) , -20); - ASSERT_EQ(offsetSubview.end(0) , 31); - ASSERT_EQ(offsetSubview.begin(1) , 0); - ASSERT_EQ(offsetSubview.end(1) , 9); + ASSERT_EQ(sum, 6 * (e0 - b0) * (e1 - b1)); +#endif + } + + // slice 2 + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + } + + { // test subview rank 4 + + Kokkos::Experimental::OffsetView sliceMe( + "offsetToSlice", {-10, 20}, {-20, 30}, {-30, 40}, {-40, 50}); + + // slice 1 + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), Kokkos::ALL(), 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), 0, Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + { + auto offsetSubview = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; + } + + // slice 2 + auto offsetSubview2a = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), + Kokkos::ALL(), 0, 0); + ASSERT_EQ(offsetSubview2a.Rank, 2) << "subview of offset is broken."; + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), 0, Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, Kokkos::ALL(), 0, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, 0, Kokkos::ALL(), 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + { + auto offsetSubview2b = Kokkos::Experimental::subview( + sliceMe, 0, 0, Kokkos::ALL(), Kokkos::ALL()); + ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; + } + // slice 3 + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0, 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0, 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL(), 0); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + { + auto offsetSubview = + Kokkos::Experimental::subview(sliceMe, 0, 0, 0, Kokkos::ALL()); + ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; + } + } +} #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) - typedef Kokkos::MDRangePolicy, Kokkos::IndexType > range_type; - typedef typename range_type::point_type point_type; - - const int b0 = offsetSubview.begin(0); - const int b1 = offsetSubview.begin(1); - - const int e0 = offsetSubview.end(0); - const int e1 = offsetSubview.end(1); - - range_type rangeP2D(point_type{ {b0, b1 } }, point_type{ { e0, e1} }); +template +KOKKOS_INLINE_FUNCTION T std_accumulate(InputIt first, InputIt last, T init, + BinaryOperation op) { + for (; first != last; ++first) { + init = op(std::move(init), *first); + } + return init; +} + +KOKKOS_INLINE_FUNCTION int element(std::initializer_list il) { + return std_accumulate(il.begin(), il.end(), 0, + [](int l, int r) { return l * 10 + r; }); +} + +template +void test_offsetview_offsets_rank1() { + using data_type = int*; + using view_type = Kokkos::View; + using index_type = Kokkos::IndexType; + using execution_policy = Kokkos::RangePolicy; + using offset_view_type = Kokkos::Experimental::OffsetView; + + view_type v("View1", 10); + Kokkos::parallel_for( + "For1", execution_policy(0, v.extent_int(0)), + KOKKOS_LAMBDA(const int i) { v(i) = element({i}); }); + + int errors; + Kokkos::parallel_reduce( + "Reduce1", execution_policy(-3, 4), + KOKKOS_LAMBDA(const int ii, int& lerrors) { + offset_view_type ov(v, {ii}); + lerrors += (ov(3) != element({3 - ii})); + }, + errors); + + ASSERT_EQ(0, errors); +} + +template +void test_offsetview_offsets_rank2() { + using data_type = int**; + using view_type = Kokkos::View; + using index_type = Kokkos::IndexType; + using execution_policy = Kokkos::RangePolicy; + using offset_view_type = Kokkos::Experimental::OffsetView; + + view_type v("View2", 10, 10); + Kokkos::parallel_for( + "For2", execution_policy(0, v.extent_int(0)), KOKKOS_LAMBDA(const int i) { + for (int j = 0; j != v.extent_int(1); ++j) { + v(i, j) = element({i, j}); + } + }); + + int errors; + Kokkos::parallel_reduce( + "Reduce2", execution_policy(-3, 4), + KOKKOS_LAMBDA(const int ii, int& lerrors) { + for (int jj = -3; jj <= 3; ++jj) { + offset_view_type ov(v, {ii, jj}); + lerrors += (ov(3, 3) != element({3 - ii, 3 - jj})); + } + }, + errors); + + ASSERT_EQ(0, errors); +} + +template +void test_offsetview_offsets_rank3() { + using data_type = int***; + using view_type = Kokkos::View; + using index_type = Kokkos::IndexType; + using execution_policy = Kokkos::RangePolicy; + using offset_view_type = Kokkos::Experimental::OffsetView; + + view_type v("View3", 10, 10, 10); + Kokkos::parallel_for( + "For3", execution_policy(0, v.extent_int(0)), KOKKOS_LAMBDA(const int i) { + for (int j = 0; j != v.extent_int(1); ++j) { + for (int k = 0; k != v.extent_int(2); ++k) { + v(i, j, k) = element({i, j, k}); + } + } + }); + + int errors; + Kokkos::parallel_reduce( + "Reduce3", execution_policy(-3, 4), + KOKKOS_LAMBDA(const int ii, int& lerrors) { + for (int jj = -3; jj <= 3; ++jj) { + for (int kk = -3; kk <= 3; ++kk) { + offset_view_type ov(v, {ii, jj, kk}); + lerrors += (ov(3, 3, 3) != element({3 - ii, 3 - jj, 3 - kk})); + } + } + }, + errors); - Kokkos::parallel_for(rangeP2D, KOKKOS_LAMBDA(const int i, const int j) { - offsetSubview(i,j) = 6; - } - ); + ASSERT_EQ(0, errors); +} +#endif - int sum = 0; - Kokkos::parallel_reduce(rangeP2D, KOKKOS_LAMBDA(const int i, const int j, int & updateMe){ - updateMe += offsetSubview(i, j); - }, sum); +TEST(TEST_CATEGORY, offsetview_construction) { + test_offsetview_construction(10); +} - ASSERT_EQ(sum, 6*(e0-b0)*(e1-b1)); -#endif - } - - // slice 2 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - } +TEST(TEST_CATEGORY, offsetview_unmanaged_construction) { + test_offsetview_unmanaged_construction(); +} - {//test subview rank 4 - - Kokkos::Experimental::OffsetView sliceMe("offsetToSlice", {-10,20}, {-20,30}, {-30,40}, {-40, 50}); - - //slice 1 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(),Kokkos::ALL(), Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), Kokkos::ALL(), 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe ,Kokkos::ALL(), 0, Kokkos::ALL(),Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe , 0, Kokkos::ALL(), Kokkos::ALL(), Kokkos::ALL() ); - ASSERT_EQ(offsetSubview.Rank, 3) << "subview of offset is broken."; - } - - // slice 2 - auto offsetSubview2a = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), Kokkos::ALL(), 0, 0); - ASSERT_EQ(offsetSubview2a.Rank, 2) << "subview of offset is broken."; - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - { - auto offsetSubview2b = Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL(), Kokkos::ALL()); - ASSERT_EQ(offsetSubview2b.Rank, 2) << "subview of offset is broken."; - } - // slice 3 - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, Kokkos::ALL(), 0, 0, 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, Kokkos::ALL(), 0, 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, 0, Kokkos::ALL(), 0); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } - { - auto offsetSubview = Kokkos::Experimental::subview(sliceMe, 0, 0, 0, Kokkos::ALL()); - ASSERT_EQ(offsetSubview.Rank, 1) << "subview of offset is broken."; - } +TEST(TEST_CATEGORY, offsetview_subview) { + test_offsetview_subview(10); +} - } +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +TEST(TEST_CATEGORY, offsetview_offsets_rank1) { + test_offsetview_offsets_rank1(); +} - } +TEST(TEST_CATEGORY, offsetview_offsets_rank2) { + test_offsetview_offsets_rank2(); +} - TEST_F( TEST_CATEGORY, offsetview_construction) { - test_offsetview_construction(10); - } - TEST_F( TEST_CATEGORY, offsetview_subview) { - test_offsetview_subview(10); - } +TEST(TEST_CATEGORY, offsetview_offsets_rank3) { + test_offsetview_offsets_rank3(); +} +#endif -} // namespace Test +} // namespace Test #endif /* CONTAINERS_UNIT_TESTS_TESTOFFSETVIEW_HPP_ */ diff --git a/lib/kokkos/containers/unit_tests/TestScatterView.hpp b/lib/kokkos/containers/unit_tests/TestScatterView.hpp index a9d97b32f3..93b69cc769 100644 --- a/lib/kokkos/containers/unit_tests/TestScatterView.hpp +++ b/lib/kokkos/containers/unit_tests/TestScatterView.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,381 +46,378 @@ #define KOKKOS_TEST_SCATTER_VIEW_HPP #include +#include namespace Test { -template +template struct test_scatter_view_impl_cls; -template -struct test_scatter_view_impl_cls -{ -public: +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterSum - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 0.0; + host_view(i, 1) = 0.0; + host_view(i, 2) = 0.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Sum"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 0.0; - host_view(i, 1) = 0.0; - host_view(i, 2) = 0.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Sum"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 10; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0) += 4.2; - scatter_access_atomic(k, 1) += 2.0; - scatter_access(k, 2) += 1.0; - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 10; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0) += 4.2; + scatter_access_atomic(k, 1) += 2.0; + scatter_access(k, 2) += 1.0; } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 84.0) / 84.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 40.0) / 40.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 20.0) / 20.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 84.0) / 84.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 40.0) / 40.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 20.0) / 20.0) < 1e-14); } + } }; +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; -template -struct test_scatter_view_impl_cls -{ -public: - - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterProd - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 1.0; + host_view(i, 1) = 1.0; + host_view(i, 2) = 1.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 1.0; - host_view(i, 1) = 1.0; - host_view(i, 2) = 1.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 4; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0) *= 4.0; - scatter_access_atomic(k, 1) *= 2.0; - scatter_access(k, 2) *= 1.0; - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 4; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0) *= 4.0; + scatter_access_atomic(k, 1) *= 2.0; + scatter_access(k, 2) *= 1.0; } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 65536.0) / 65536.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 256.0) / 256.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 65536.0) / 65536.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 256.0) / 256.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); } + } }; +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; -template -struct test_scatter_view_impl_cls -{ -public: - - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterMin - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 999999.0; + host_view(i, 1) = 999999.0; + host_view(i, 2) = 999999.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 999999.0; - host_view(i, 1) = 999999.0; - host_view(i, 2) = 999999.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 4; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0).update((double)(j+1)*4); - scatter_access_atomic(k, 1).update((double)(j+1)*2.0); - scatter_access(k, 2).update((double)(j+1)*1.0); - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 4; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0).update((double)(j + 1) * 4); + scatter_access_atomic(k, 1).update((double)(j + 1) * 2.0); + scatter_access(k, 2).update((double)(j + 1) * 1.0); } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 4.0) / 4.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 2.0) / 2.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 4.0) / 4.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 2.0) / 2.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 1.0) / 1.0) < 1e-14); } + } }; +template +struct test_scatter_view_impl_cls { + public: + typedef Kokkos::Experimental::ScatterView + scatter_view_type; -template -struct test_scatter_view_impl_cls -{ -public: - - typedef Kokkos::Experimental::ScatterView - < double*[3] - , Layout - , ExecSpace - , Kokkos::Experimental::ScatterMax - , duplication - , contribution - > scatter_view_type; + typedef Kokkos::View orig_view_type; - typedef Kokkos::View orig_view_type; + scatter_view_type scatter_view; + int scatterSize; + test_scatter_view_impl_cls(const scatter_view_type& view) { + scatter_view = view; + scatterSize = 0; + } - scatter_view_type scatter_view; - int scatterSize; + void initialize(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + host_view(i, 0) = 0.0; + host_view(i, 1) = 0.0; + host_view(i, 2) = 0.0; + } + Kokkos::fence(); + Kokkos::deep_copy(orig, host_view); + } - test_scatter_view_impl_cls(const scatter_view_type& view){ - scatter_view = view; - scatterSize = 0; - } + void run_parallel(int n) { + scatterSize = n; + auto policy = Kokkos::RangePolicy(0, n); + Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); + } - void initialize(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - host_view(i, 0) = 0.0; - host_view(i, 1) = 0.0; - host_view(i, 2) = 0.0; - } - Kokkos::fence(); - Kokkos::deep_copy(orig, host_view); - } - - void run_parallel(int n) { - scatterSize = n; - auto policy = Kokkos::RangePolicy(0, n); - Kokkos::parallel_for(policy, *this, "scatter_view_test: Prod"); - } - - KOKKOS_INLINE_FUNCTION - void operator()(int i) const { - auto scatter_access = scatter_view.access(); - auto scatter_access_atomic = scatter_view.template access(); - for (int j = 0; j < 4; ++j) { - auto k = (i + j) % scatterSize; - scatter_access(k, 0).update((double)(j+1)*4); - scatter_access_atomic(k, 1).update((double)(j+1)*2.0); - scatter_access(k, 2).update((double)(j+1)*1.0); - } + KOKKOS_INLINE_FUNCTION + void operator()(int i) const { + auto scatter_access = scatter_view.access(); + auto scatter_access_atomic = + scatter_view.template access(); + for (int j = 0; j < 4; ++j) { + auto k = (i + j) % scatterSize; + scatter_access(k, 0).update((double)(j + 1) * 4); + scatter_access_atomic(k, 1).update((double)(j + 1) * 2.0); + scatter_access(k, 2).update((double)(j + 1) * 1.0); } + } - void validateResults(orig_view_type orig) { - auto host_view = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); - Kokkos::fence(); - for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); ++i) { - auto val0 = host_view(i, 0); - auto val1 = host_view(i, 1); - auto val2 = host_view(i, 2); - EXPECT_TRUE(std::fabs((val0 - 16.0) / 16.0) < 1e-14); - EXPECT_TRUE(std::fabs((val1 - 8.0) / 8.0) < 1e-14); - EXPECT_TRUE(std::fabs((val2 - 4.0) / 4.0) < 1e-14); - } + void validateResults(orig_view_type orig) { + auto host_view = + Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), orig); + Kokkos::fence(); + for (typename decltype(host_view)::size_type i = 0; i < host_view.extent(0); + ++i) { + auto val0 = host_view(i, 0); + auto val1 = host_view(i, 1); + auto val2 = host_view(i, 2); + EXPECT_TRUE(std::fabs((val0 - 16.0) / 16.0) < 1e-14); + EXPECT_TRUE(std::fabs((val1 - 8.0) / 8.0) < 1e-14); + EXPECT_TRUE(std::fabs((val2 - 4.0) / 4.0) < 1e-14); } + } }; - - -template -struct test_scatter_view_config -{ +template +struct test_scatter_view_config { public: - typedef typename test_scatter_view_impl_cls::scatter_view_type scatter_view_def; - typedef typename test_scatter_view_impl_cls::orig_view_type orig_view_def; - - test_scatter_view_config() { - } - - void run_test(int n) - { - //Test creation via create_scatter_view - { - orig_view_def original_view("original_view", n); - scatter_view_def scatter_view = Kokkos::Experimental::create_scatter_view - < op - , duplication - , contribution - > (original_view); - - test_scatter_view_impl_cls scatter_view_test_impl(scatter_view); - scatter_view_test_impl.initialize(original_view); - scatter_view_test_impl.run_parallel(n); - - Kokkos::Experimental::contribute(original_view, scatter_view); - scatter_view.reset_except(original_view); - - scatter_view_test_impl.run_parallel(n); - - Kokkos::Experimental::contribute(original_view, scatter_view); - Kokkos::fence(); + typedef + typename test_scatter_view_impl_cls::scatter_view_type + scatter_view_def; + typedef typename test_scatter_view_impl_cls::orig_view_type + orig_view_def; + + test_scatter_view_config() {} + + void run_test(int n) { + // Test creation via create_scatter_view + { + orig_view_def original_view("original_view", n); + scatter_view_def scatter_view = Kokkos::Experimental::create_scatter_view< + op, duplication, contribution>(original_view); + + test_scatter_view_impl_cls + scatter_view_test_impl(scatter_view); + scatter_view_test_impl.initialize(original_view); + scatter_view_test_impl.run_parallel(n); + + Kokkos::Experimental::contribute(original_view, scatter_view); + scatter_view.reset_except(original_view); + + scatter_view_test_impl.run_parallel(n); + + Kokkos::Experimental::contribute(original_view, scatter_view); + Kokkos::fence(); - scatter_view_test_impl.validateResults(original_view); + scatter_view_test_impl.validateResults(original_view); - { + { scatter_view_def persistent_view("persistent", n); auto result_view = persistent_view.subview(); contribute(result_view, persistent_view); Kokkos::fence(); - } - } - //Test creation via constructor - { - orig_view_def original_view("original_view", n); - scatter_view_def scatter_view(original_view); + } + } + // Test creation via constructor + { + orig_view_def original_view("original_view", n); + scatter_view_def scatter_view(original_view); - test_scatter_view_impl_cls scatter_view_test_impl(scatter_view); - scatter_view_test_impl.initialize(original_view); - scatter_view_test_impl.run_parallel(n); + test_scatter_view_impl_cls + scatter_view_test_impl(scatter_view); + scatter_view_test_impl.initialize(original_view); + scatter_view_test_impl.run_parallel(n); - Kokkos::Experimental::contribute(original_view, scatter_view); - scatter_view.reset_except(original_view); + Kokkos::Experimental::contribute(original_view, scatter_view); + scatter_view.reset_except(original_view); - scatter_view_test_impl.run_parallel(n); + scatter_view_test_impl.run_parallel(n); - Kokkos::Experimental::contribute(original_view, scatter_view); - Kokkos::fence(); + Kokkos::Experimental::contribute(original_view, scatter_view); + Kokkos::fence(); - scatter_view_test_impl.validateResults(original_view); + scatter_view_test_impl.validateResults(original_view); - { + { scatter_view_def persistent_view("persistent", n); auto result_view = persistent_view.subview(); contribute(result_view, persistent_view); Kokkos::fence(); - } - } - } - + } + } + } }; - template struct TestDuplicatedScatterView { TestDuplicatedScatterView(int n) { // ScatterSum test - test_scatter_view_config test_sv_right_config; + test_scatter_view_config< + ExecSpace, Kokkos::LayoutRight, Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic, ScatterType> + test_sv_right_config; test_sv_right_config.run_test(n); - test_scatter_view_config test_sv_left_config; + test_scatter_view_config< + ExecSpace, Kokkos::LayoutLeft, Kokkos::Experimental::ScatterDuplicated, + Kokkos::Experimental::ScatterNonAtomic, ScatterType> + test_sv_left_config; test_sv_left_config.run_test(n); } }; @@ -429,8 +427,7 @@ struct TestDuplicatedScatterView { // UniqueToken can support it template struct TestDuplicatedScatterView { - TestDuplicatedScatterView(int) { - } + TestDuplicatedScatterView(int) {} }; #endif @@ -439,14 +436,12 @@ struct TestDuplicatedScatterView { // UniqueToken can support it template struct TestDuplicatedScatterView { - TestDuplicatedScatterView(int) { - } + TestDuplicatedScatterView(int) {} }; #endif template -void test_scatter_view(int n) -{ +void test_scatter_view(int n) { // all of these configurations should compile okay, but only some of them are // correct and/or sensible in terms of memory use Kokkos::Experimental::UniqueToken unique_token{ExecSpace()}; @@ -456,33 +451,37 @@ void test_scatter_view(int n) // we also test OpenMP with one thread: LAMMPS cares about that) if (unique_token.size() == 1) { test_scatter_view_config test_sv_config; + Kokkos::Experimental::ScatterNonDuplicated, + Kokkos::Experimental::ScatterNonAtomic, + ScatterType> + test_sv_config; test_sv_config.run_test(n); } #ifdef KOKKOS_ENABLE_SERIAL if (!std::is_same::value) { #endif - test_scatter_view_config test_sv_config; - test_sv_config.run_test(n); + test_scatter_view_config + test_sv_config; + test_sv_config.run_test(n); #ifdef KOKKOS_ENABLE_SERIAL } #endif // with hundreds of threads we were running out of memory. // limit (n) so that duplication doesn't exceed 8GB - constexpr std::size_t maximum_allowed_total_bytes = 8ull * 1024ull * 1024ull * 1024ull; - std::size_t const maximum_allowed_copy_bytes = maximum_allowed_total_bytes / std::size_t(unique_token.size()); + constexpr std::size_t maximum_allowed_total_bytes = + 8ull * 1024ull * 1024ull * 1024ull; + std::size_t const maximum_allowed_copy_bytes = + maximum_allowed_total_bytes / std::size_t(unique_token.size()); constexpr std::size_t bytes_per_value = sizeof(double) * 3; - std::size_t const maximum_allowed_copy_values = maximum_allowed_copy_bytes / bytes_per_value; + std::size_t const maximum_allowed_copy_values = + maximum_allowed_copy_bytes / bytes_per_value; n = std::min(n, int(maximum_allowed_copy_values)); TestDuplicatedScatterView duptest(n); } -TEST_F( TEST_CATEGORY, scatterview) { +TEST(TEST_CATEGORY, scatterview) { #ifndef KOKKOS_ENABLE_ROCM test_scatter_view(10); test_scatter_view(10); @@ -492,17 +491,22 @@ TEST_F( TEST_CATEGORY, scatterview) { #ifdef KOKKOS_ENABLE_DEBUG int big_n = 100 * 1000; #else - int big_n = 10 * 1000 * 1000; + +#ifdef KOKKOS_ENABLE_SERIAL + bool is_serial = std::is_same::value; + int big_n = is_serial ? 100 * 1000 : 10000 * 1000; +#else + int big_n = 10000 * 1000; +#endif + #endif - test_scatter_view(big_n); - test_scatter_view(big_n); - test_scatter_view(big_n); - test_scatter_view(big_n); + test_scatter_view(big_n); + test_scatter_view(big_n); + test_scatter_view(big_n); + test_scatter_view(big_n); #endif } -} // namespace Test - -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP - +} // namespace Test +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp b/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp index 7ba307079f..15c190242c 100644 --- a/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp +++ b/lib/kokkos/containers/unit_tests/TestStaticCrsGraph.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,233 +53,244 @@ namespace Test { namespace TestStaticCrsGraph { -template< class Space > -void run_test_graph() -{ - typedef Kokkos::StaticCrsGraph< unsigned , Space > dView ; - typedef typename dView::HostMirror hView ; +template +void run_test_graph() { + typedef Kokkos::StaticCrsGraph dView; + typedef typename dView::HostMirror hView; - const unsigned LENGTH = 1000 ; - dView dx ; - hView hx ; + const unsigned LENGTH = 1000; + dView dx; + hView hx; - std::vector< std::vector< int > > graph( LENGTH ); + std::vector > graph(LENGTH); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { graph[i].reserve(8); - for ( size_t j = 0 ; j < 8 ; ++j ) { - graph[i].push_back( i + j * 3 ); + for (size_t j = 0; j < 8; ++j) { + graph[i].push_back(i + j * 3); } } - dx = Kokkos::create_staticcrsgraph( "dx" , graph ); - hx = Kokkos::create_mirror( dx ); + dx = Kokkos::create_staticcrsgraph("dx", graph); + hx = Kokkos::create_mirror(dx); - ASSERT_EQ( hx.row_map.extent(0) - 1 , LENGTH ); + ASSERT_EQ(hx.row_map.extent(0) - 1, LENGTH); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { const size_t begin = hx.row_map[i]; - const size_t n = hx.row_map[i+1] - begin ; - ASSERT_EQ( n , graph[i].size() ); - for ( size_t j = 0 ; j < n ; ++j ) { - ASSERT_EQ( (int) hx.entries( j + begin ) , graph[i][j] ); + const size_t n = hx.row_map[i + 1] - begin; + ASSERT_EQ(n, graph[i].size()); + for (size_t j = 0; j < n; ++j) { + ASSERT_EQ((int)hx.entries(j + begin), graph[i][j]); } } // Test row view access - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { auto rowView = hx.rowConst(i); - ASSERT_EQ( rowView.length, graph[i].size() ); - for ( size_t j = 0 ; j < rowView.length ; ++j ) { - ASSERT_EQ( rowView.colidx( j ) , graph[i][j] ); - ASSERT_EQ( rowView( j ) , graph[i][j] ); + ASSERT_EQ(rowView.length, graph[i].size()); + for (size_t j = 0; j < rowView.length; ++j) { + ASSERT_EQ(rowView.colidx(j), graph[i][j]); + ASSERT_EQ(rowView(j), graph[i][j]); } } } -template< class Space > -void run_test_graph2() -{ - typedef Kokkos::StaticCrsGraph< unsigned[3] , Space > dView ; - typedef typename dView::HostMirror hView ; +template +void run_test_graph2() { + typedef Kokkos::StaticCrsGraph dView; + typedef typename dView::HostMirror hView; - const unsigned LENGTH = 10 ; + const unsigned LENGTH = 10; - std::vector< size_t > sizes( LENGTH ); + std::vector sizes(LENGTH); - size_t total_length = 0 ; + size_t total_length = 0; - for ( size_t i = 0 ; i < LENGTH ; ++i ) { - total_length += ( sizes[i] = 6 + i % 4 ); + for (size_t i = 0; i < LENGTH; ++i) { + total_length += (sizes[i] = 6 + i % 4); } - dView dx = Kokkos::create_staticcrsgraph( "test" , sizes ); - hView hx = Kokkos::create_mirror( dx ); - hView mx = Kokkos::create_mirror( dx ); + dView dx = Kokkos::create_staticcrsgraph("test", sizes); + hView hx = Kokkos::create_mirror(dx); + hView mx = Kokkos::create_mirror(dx); - ASSERT_EQ( (size_t) dx.row_map.extent(0) , (size_t) LENGTH + 1 ); - ASSERT_EQ( (size_t) hx.row_map.extent(0) , (size_t) LENGTH + 1 ); - ASSERT_EQ( (size_t) mx.row_map.extent(0) , (size_t) LENGTH + 1 ); + ASSERT_EQ((size_t)dx.row_map.extent(0), (size_t)LENGTH + 1); + ASSERT_EQ((size_t)hx.row_map.extent(0), (size_t)LENGTH + 1); + ASSERT_EQ((size_t)mx.row_map.extent(0), (size_t)LENGTH + 1); - ASSERT_EQ( (size_t) dx.entries.extent(0) , (size_t) total_length ); - ASSERT_EQ( (size_t) hx.entries.extent(0) , (size_t) total_length ); - ASSERT_EQ( (size_t) mx.entries.extent(0) , (size_t) total_length ); + ASSERT_EQ((size_t)dx.entries.extent(0), (size_t)total_length); + ASSERT_EQ((size_t)hx.entries.extent(0), (size_t)total_length); + ASSERT_EQ((size_t)mx.entries.extent(0), (size_t)total_length); - ASSERT_EQ( (size_t) dx.entries.extent(1) , (size_t) 3 ); - ASSERT_EQ( (size_t) hx.entries.extent(1) , (size_t) 3 ); - ASSERT_EQ( (size_t) mx.entries.extent(1) , (size_t) 3 ); + ASSERT_EQ((size_t)dx.entries.extent(1), (size_t)3); + ASSERT_EQ((size_t)hx.entries.extent(1), (size_t)3); + ASSERT_EQ((size_t)mx.entries.extent(1), (size_t)3); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { const size_t entry_begin = hx.row_map[i]; - const size_t entry_end = hx.row_map[i+1]; - for ( size_t j = entry_begin ; j < entry_end ; ++j ) { - hx.entries(j,0) = j + 1 ; - hx.entries(j,1) = j + 2 ; - hx.entries(j,2) = j + 3 ; + const size_t entry_end = hx.row_map[i + 1]; + for (size_t j = entry_begin; j < entry_end; ++j) { + hx.entries(j, 0) = j + 1; + hx.entries(j, 1) = j + 2; + hx.entries(j, 2) = j + 3; } } - Kokkos::deep_copy( dx.entries , hx.entries ); - Kokkos::deep_copy( mx.entries , dx.entries ); + Kokkos::deep_copy(dx.entries, hx.entries); + Kokkos::deep_copy(mx.entries, dx.entries); - ASSERT_EQ( mx.row_map.extent(0) , (size_t) LENGTH + 1 ); + ASSERT_EQ(mx.row_map.extent(0), (size_t)LENGTH + 1); - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { const size_t entry_begin = mx.row_map[i]; - const size_t entry_end = mx.row_map[i+1]; - ASSERT_EQ( ( entry_end - entry_begin ) , sizes[i] ); - for ( size_t j = entry_begin ; j < entry_end ; ++j ) { - ASSERT_EQ( (size_t) mx.entries( j , 0 ) , ( j + 1 ) ); - ASSERT_EQ( (size_t) mx.entries( j , 1 ) , ( j + 2 ) ); - ASSERT_EQ( (size_t) mx.entries( j , 2 ) , ( j + 3 ) ); + const size_t entry_end = mx.row_map[i + 1]; + ASSERT_EQ((entry_end - entry_begin), sizes[i]); + for (size_t j = entry_begin; j < entry_end; ++j) { + ASSERT_EQ((size_t)mx.entries(j, 0), (j + 1)); + ASSERT_EQ((size_t)mx.entries(j, 1), (j + 2)); + ASSERT_EQ((size_t)mx.entries(j, 2), (j + 3)); } } } -template< class Space > -void run_test_graph3(size_t B, size_t N) -{ +template +void run_test_graph3(size_t B, size_t N) { srand(10310); - typedef Kokkos::StaticCrsGraph< int , Space > dView ; - typedef typename dView::HostMirror hView ; + typedef Kokkos::StaticCrsGraph dView; + typedef typename dView::HostMirror hView; - const unsigned LENGTH = 2000 ; + const unsigned LENGTH = 2000; - std::vector< size_t > sizes( LENGTH ); + std::vector sizes(LENGTH); - size_t total_length = 0 ; + size_t total_length = 0; - for ( size_t i = 0 ; i < LENGTH ; ++i ) { - sizes[i] = rand()%1000; + for (size_t i = 0; i < LENGTH; ++i) { + sizes[i] = rand() % 1000; } - sizes[1] = N; + sizes[1] = N; sizes[1998] = N; - for ( size_t i = 0 ; i < LENGTH ; ++i ) { + for (size_t i = 0; i < LENGTH; ++i) { total_length += sizes[i]; } - int C = 0; - dView dx = Kokkos::create_staticcrsgraph( "test" , sizes ); - dx.create_block_partitioning(B,C); - hView hx = Kokkos::create_mirror( dx ); + int C = 0; + dView dx = Kokkos::create_staticcrsgraph("test", sizes); + dx.create_block_partitioning(B, C); + hView hx = Kokkos::create_mirror(dx); - for( size_t i = 0; i2*((hx.row_map(hx.numRows())+C*hx.numRows())/B))&&(hx.row_block_offsets(i+1)>hx.row_block_offsets(i)+1)); + ASSERT_FALSE( + (ne > 2 * ((hx.row_map(hx.numRows()) + C * hx.numRows()) / B)) && + (hx.row_block_offsets(i + 1) > hx.row_block_offsets(i) + 1)); } } -template< class Space > -void run_test_graph4() -{ +template +void run_test_graph4() { typedef unsigned ordinal_type; typedef Kokkos::LayoutRight layout_type; typedef Space space_type; typedef Kokkos::MemoryUnmanaged memory_traits_type; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - typedef Kokkos::StaticCrsGraph< ordinal_type , layout_type , space_type , ordinal_type , memory_traits_type > dView ; + typedef Kokkos::StaticCrsGraph + dView; #else - typedef Kokkos::StaticCrsGraph< ordinal_type , layout_type , space_type , memory_traits_type > dView ; + typedef Kokkos::StaticCrsGraph + dView; #endif - typedef typename dView::HostMirror hView ; + typedef typename dView::HostMirror hView; - dView dx ; + dView dx; - // StaticCrsGraph with Unmanaged trait will contain row_map and entries members - // with the Unmanaged memory trait. - // Use of such a StaticCrsGraph requires an allocaton of memory for the unmanaged views - // to wrap. + // StaticCrsGraph with Unmanaged trait will contain row_map and entries + // members with the Unmanaged memory trait. Use of such a StaticCrsGraph + // requires an allocaton of memory for the unmanaged views to wrap. // // In this test, a graph (via raw arrays) resides on the host. - // The pointers are wrapped by unmanaged Views. - // To make use of this on the device, managed device Views are created (allocation required), - // and data from the unmanaged host views is deep copied to the device Views - // Unmanaged views of the appropriate type wrap the device data and are assigned to - // their corresponding unmanaged view members of the unmanaged StaticCrsGraph + // The pointers are wrapped by unmanaged Views. + // To make use of this on the device, managed device Views are created + // (allocation required), and data from the unmanaged host views is deep + // copied to the device Views Unmanaged views of the appropriate type wrap the + // device data and are assigned to their corresponding unmanaged view members + // of the unmanaged StaticCrsGraph // Data types for raw pointers storing StaticCrsGraph info typedef typename dView::size_type ptr_row_map_type; typedef typename dView::data_type ptr_entries_type; const ordinal_type numRows = 8; - const ordinal_type nnz = 24; - ptr_row_map_type ptrRaw[] = {0, 4, 8, 10, 12, 14, 16, 20, 24}; - ptr_entries_type indRaw[] = {0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 2, 3, 4, 5, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7}; + const ordinal_type nnz = 24; + ptr_row_map_type ptrRaw[] = {0, 4, 8, 10, 12, 14, 16, 20, 24}; + ptr_entries_type indRaw[] = {0, 1, 4, 5, 0, 1, 4, 5, 2, 3, 2, 3, + 4, 5, 4, 5, 2, 3, 6, 7, 2, 3, 6, 7}; // Wrap pointers in unmanaged host views - typedef typename hView::row_map_type local_row_map_type ; - typedef typename hView::entries_type local_entries_type ; - local_row_map_type unman_row_map( &(ptrRaw[0]) , numRows+1 ); - local_entries_type unman_entries( &(indRaw[0]) , nnz ); + typedef typename hView::row_map_type local_row_map_type; + typedef typename hView::entries_type local_entries_type; + local_row_map_type unman_row_map(&(ptrRaw[0]), numRows + 1); + local_entries_type unman_entries(&(indRaw[0]), nnz); - hView hx ; - hx = hView( unman_entries, unman_row_map ); + hView hx; + hx = hView(unman_entries, unman_row_map); // Create the device Views for copying the host arrays into - // An allocation is needed on the device for the unmanaged StaticCrsGraph to wrap the pointer - typedef typename Kokkos::View< ptr_row_map_type*, layout_type, space_type > d_row_map_view_type; - typedef typename Kokkos::View< ptr_entries_type*, layout_type, space_type > d_entries_view_type; - - d_row_map_view_type tmp_row_map( "tmp_row_map", numRows+1 ); - d_entries_view_type tmp_entries( "tmp_entries", nnz ); - - Kokkos::deep_copy (tmp_row_map, unman_row_map); - Kokkos::deep_copy (tmp_entries, unman_entries); - - // Wrap the pointer in unmanaged View and assign to the corresponding StaticCrsGraph member - dx.row_map = typename dView::row_map_type(tmp_row_map.data(), numRows+1); + // An allocation is needed on the device for the unmanaged StaticCrsGraph to + // wrap the pointer + typedef typename Kokkos::View + d_row_map_view_type; + typedef typename Kokkos::View + d_entries_view_type; + + d_row_map_view_type tmp_row_map("tmp_row_map", numRows + 1); + d_entries_view_type tmp_entries("tmp_entries", nnz); + + Kokkos::deep_copy(tmp_row_map, unman_row_map); + Kokkos::deep_copy(tmp_entries, unman_entries); + + // Wrap the pointer in unmanaged View and assign to the corresponding + // StaticCrsGraph member + dx.row_map = typename dView::row_map_type(tmp_row_map.data(), numRows + 1); dx.entries = typename dView::entries_type(tmp_entries.data(), nnz); - ASSERT_TRUE((std::is_same< typename dView::row_map_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); - ASSERT_TRUE((std::is_same< typename dView::entries_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); - ASSERT_TRUE((std::is_same< typename hView::row_map_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); - ASSERT_TRUE((std::is_same< typename hView::entries_type::memory_traits , Kokkos::MemoryUnmanaged >::value)); + ASSERT_TRUE((std::is_same::value)); + ASSERT_TRUE((std::is_same::value)); + ASSERT_TRUE((std::is_same::value)); + ASSERT_TRUE((std::is_same::value)); } } /* namespace TestStaticCrsGraph */ -TEST_F( TEST_CATEGORY , staticcrsgraph ) -{ - TestStaticCrsGraph::run_test_graph< TEST_EXECSPACE >(); - TestStaticCrsGraph::run_test_graph2< TEST_EXECSPACE >(); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 0); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 1000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 10000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(1, 100000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 0); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 1000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 10000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(3, 100000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 0); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 1000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 10000); - TestStaticCrsGraph::run_test_graph3< TEST_EXECSPACE >(75, 100000); - TestStaticCrsGraph::run_test_graph4< TEST_EXECSPACE >(); -} +TEST(TEST_CATEGORY, staticcrsgraph) { + TestStaticCrsGraph::run_test_graph(); + TestStaticCrsGraph::run_test_graph2(); + TestStaticCrsGraph::run_test_graph3(1, 0); + TestStaticCrsGraph::run_test_graph3(1, 1000); + TestStaticCrsGraph::run_test_graph3(1, 10000); + TestStaticCrsGraph::run_test_graph3(1, 100000); + TestStaticCrsGraph::run_test_graph3(3, 0); + TestStaticCrsGraph::run_test_graph3(3, 1000); + TestStaticCrsGraph::run_test_graph3(3, 10000); + TestStaticCrsGraph::run_test_graph3(3, 100000); + TestStaticCrsGraph::run_test_graph3(75, 0); + TestStaticCrsGraph::run_test_graph3(75, 1000); + TestStaticCrsGraph::run_test_graph3(75, 10000); + TestStaticCrsGraph::run_test_graph3(75, 100000); + TestStaticCrsGraph::run_test_graph4(); } +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp b/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp index 2d34267df3..82782d3bf4 100644 --- a/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp +++ b/lib/kokkos/containers/unit_tests/TestUnorderedMap.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,8 +52,7 @@ namespace Test { namespace Impl { template -struct TestInsert -{ +struct TestInsert { typedef MapType map_type; typedef typename map_type::execution_space execution_space; typedef uint32_t value_type; @@ -61,14 +61,10 @@ struct TestInsert uint32_t inserts; uint32_t collisions; - TestInsert( map_type arg_map, uint32_t arg_inserts, uint32_t arg_collisions) - : map(arg_map) - , inserts(arg_inserts) - , collisions(arg_collisions) - {} + TestInsert(map_type arg_map, uint32_t arg_inserts, uint32_t arg_collisions) + : map(arg_map), inserts(arg_inserts), collisions(arg_collisions) {} - void testit( bool rehash_on_fail = true ) - { + void testit(bool rehash_on_fail = true) { execution_space().fence(); uint32_t failed_count = 0; @@ -77,138 +73,127 @@ struct TestInsert Kokkos::parallel_reduce(inserts, *this, failed_count); if (rehash_on_fail && failed_count > 0u) { - const uint32_t new_capacity = map.capacity() + ((map.capacity()*3ull)/20u) + failed_count/collisions ; - map.rehash( new_capacity ); + const uint32_t new_capacity = map.capacity() + + ((map.capacity() * 3ull) / 20u) + + failed_count / collisions; + map.rehash(new_capacity); } } while (rehash_on_fail && failed_count > 0u); execution_space().fence(); } - KOKKOS_INLINE_FUNCTION - void init( value_type & failed_count ) const { failed_count = 0; } + void init(value_type &failed_count) const { failed_count = 0; } KOKKOS_INLINE_FUNCTION - void join( volatile value_type & failed_count, const volatile value_type & count ) const - { failed_count += count; } + void join(volatile value_type &failed_count, + const volatile value_type &count) const { + failed_count += count; + } KOKKOS_INLINE_FUNCTION - void operator()(uint32_t i, value_type & failed_count) const - { - const uint32_t key = Near ? i/collisions : i%(inserts/collisions); - if (map.insert(key,i).failed()) ++failed_count; + void operator()(uint32_t i, value_type &failed_count) const { + const uint32_t key = Near ? i / collisions : i % (inserts / collisions); + if (map.insert(key, i).failed()) ++failed_count; } - }; - template - struct TestErase - { - typedef TestErase self_type; +template +struct TestErase { + typedef TestErase self_type; - typedef MapType map_type; - typedef typename MapType::execution_space execution_space; + typedef MapType map_type; + typedef typename MapType::execution_space execution_space; - map_type m_map; - uint32_t m_num_erase; - uint32_t m_num_duplicates; + map_type m_map; + uint32_t m_num_erase; + uint32_t m_num_duplicates; - TestErase(map_type map, uint32_t num_erases, uint32_t num_duplicates) - : m_map(map) - , m_num_erase(num_erases) - , m_num_duplicates(num_duplicates) - {} + TestErase(map_type map, uint32_t num_erases, uint32_t num_duplicates) + : m_map(map), m_num_erase(num_erases), m_num_duplicates(num_duplicates) {} - void testit() - { - execution_space().fence(); - Kokkos::parallel_for(m_num_erase, *this); - execution_space().fence(); - } - - KOKKOS_INLINE_FUNCTION - void operator()(typename execution_space::size_type i) const - { - if (Near) { - m_map.erase(i/m_num_duplicates); - } - else { - m_map.erase(i%(m_num_erase/m_num_duplicates)); - } + void testit() { + execution_space().fence(); + Kokkos::parallel_for(m_num_erase, *this); + execution_space().fence(); + } + KOKKOS_INLINE_FUNCTION + void operator()(typename execution_space::size_type i) const { + if (Near) { + m_map.erase(i / m_num_duplicates); + } else { + m_map.erase(i % (m_num_erase / m_num_duplicates)); } - }; + } +}; - template - struct TestFind - { - typedef MapType map_type; - typedef typename MapType::execution_space::execution_space execution_space; - typedef uint32_t value_type; - - map_type m_map; - uint32_t m_num_insert; - uint32_t m_num_duplicates; - uint32_t m_max_key; - - TestFind(map_type map, uint32_t num_inserts, uint32_t num_duplicates) - : m_map(map) - , m_num_insert(num_inserts) - , m_num_duplicates(num_duplicates) - , m_max_key( ((num_inserts + num_duplicates) - 1)/num_duplicates ) - {} - - void testit(value_type &errors) - { - execution_space().fence(); - Kokkos::parallel_reduce(m_map.capacity(), *this, errors); - execution_space().fence(); - } +template +struct TestFind { + typedef MapType map_type; + typedef typename MapType::execution_space::execution_space execution_space; + typedef uint32_t value_type; - KOKKOS_INLINE_FUNCTION - static void init( value_type & dst) - { - dst = 0; - } + map_type m_map; + uint32_t m_num_insert; + uint32_t m_num_duplicates; + uint32_t m_max_key; - KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & dst, const volatile value_type & src) - { dst += src; } + TestFind(map_type map, uint32_t num_inserts, uint32_t num_duplicates) + : m_map(map), + m_num_insert(num_inserts), + m_num_duplicates(num_duplicates), + m_max_key(((num_inserts + num_duplicates) - 1) / num_duplicates) {} - KOKKOS_INLINE_FUNCTION - void operator()(typename execution_space::size_type i, value_type & errors) const - { - const bool expect_to_find_i = (i < m_max_key); + void testit(value_type &errors) { + execution_space().fence(); + Kokkos::parallel_reduce(m_map.capacity(), *this, errors); + execution_space().fence(); + } - const bool exists = m_map.exists(i); + KOKKOS_INLINE_FUNCTION + static void init(value_type &dst) { dst = 0; } - if (expect_to_find_i && !exists) ++errors; - if (!expect_to_find_i && exists) ++errors; - } - }; + KOKKOS_INLINE_FUNCTION + static void join(volatile value_type &dst, const volatile value_type &src) { + dst += src; + } + + KOKKOS_INLINE_FUNCTION + void operator()(typename execution_space::size_type i, + value_type &errors) const { + const bool expect_to_find_i = (i < m_max_key); -} // namespace Impl + const bool exists = m_map.exists(i); + if (expect_to_find_i && !exists) ++errors; + if (!expect_to_find_i && exists) ++errors; + } +}; +} // namespace Impl template -void test_insert( uint32_t num_nodes , uint32_t num_inserts , uint32_t num_duplicates , bool near ) -{ - typedef Kokkos::UnorderedMap map_type; - typedef Kokkos::UnorderedMap const_map_type; +void test_insert(uint32_t num_nodes, uint32_t num_inserts, + uint32_t num_duplicates, bool near) { + typedef Kokkos::UnorderedMap map_type; + typedef Kokkos::UnorderedMap + const_map_type; - const uint32_t expected_inserts = (num_inserts + num_duplicates -1u) / num_duplicates; + const uint32_t expected_inserts = + (num_inserts + num_duplicates - 1u) / num_duplicates; map_type map; - map.rehash(num_nodes,false); + map.rehash(num_nodes, false); if (near) { - Impl::TestInsert test_insert(map, num_inserts, num_duplicates); + Impl::TestInsert test_insert(map, num_inserts, + num_duplicates); test_insert.testit(); - } else - { - Impl::TestInsert test_insert(map, num_inserts, num_duplicates); + } else { + Impl::TestInsert test_insert(map, num_inserts, + num_duplicates); test_insert.testit(); } @@ -220,19 +205,21 @@ void test_insert( uint32_t num_nodes , uint32_t num_inserts , uint32_t num_dupli const uint32_t map_size = map.size(); - ASSERT_FALSE( map.failed_insert()); + ASSERT_FALSE(map.failed_insert()); { EXPECT_EQ(expected_inserts, map_size); { uint32_t find_errors = 0; - Impl::TestFind test_find(map, num_inserts, num_duplicates); + Impl::TestFind test_find(map, num_inserts, + num_duplicates); test_find.testit(find_errors); - EXPECT_EQ( 0u, find_errors); + EXPECT_EQ(0u, find_errors); } map.begin_erase(); - Impl::TestErase test_erase(map, num_inserts, num_duplicates); + Impl::TestErase test_erase(map, num_inserts, + num_duplicates); test_erase.testit(); map.end_erase(); EXPECT_EQ(0u, map.size()); @@ -240,56 +227,53 @@ void test_insert( uint32_t num_nodes , uint32_t num_inserts , uint32_t num_dupli } template -void test_failed_insert( uint32_t num_nodes) -{ - typedef Kokkos::UnorderedMap map_type; +void test_failed_insert(uint32_t num_nodes) { + typedef Kokkos::UnorderedMap map_type; map_type map(num_nodes); - Impl::TestInsert test_insert(map, 2u*num_nodes, 1u); + Impl::TestInsert test_insert(map, 2u * num_nodes, 1u); test_insert.testit(false /*don't rehash on fail*/); typename Device::execution_space().fence(); - EXPECT_TRUE( map.failed_insert() ); + EXPECT_TRUE(map.failed_insert()); } - - template -void test_deep_copy( uint32_t num_nodes ) -{ - typedef Kokkos::UnorderedMap map_type; - typedef Kokkos::UnorderedMap const_map_type; +void test_deep_copy(uint32_t num_nodes) { + typedef Kokkos::UnorderedMap map_type; + typedef Kokkos::UnorderedMap + const_map_type; - typedef typename map_type::HostMirror host_map_type ; - // typedef Kokkos::UnorderedMap host_map_type; + typedef typename map_type::HostMirror host_map_type; + // typedef Kokkos::UnorderedMap host_map_type; map_type map; - map.rehash(num_nodes,false); + map.rehash(num_nodes, false); { Impl::TestInsert test_insert(map, num_nodes, 1); test_insert.testit(); - ASSERT_EQ( map.size(), num_nodes); - ASSERT_FALSE( map.failed_insert() ); + ASSERT_EQ(map.size(), num_nodes); + ASSERT_FALSE(map.failed_insert()); { uint32_t find_errors = 0; Impl::TestFind test_find(map, num_nodes, 1); test_find.testit(find_errors); - EXPECT_EQ( find_errors, 0u); + EXPECT_EQ(find_errors, 0u); } - } host_map_type hmap; Kokkos::deep_copy(hmap, map); - ASSERT_EQ( map.size(), hmap.size()); - ASSERT_EQ( map.capacity(), hmap.capacity()); + ASSERT_EQ(map.size(), hmap.size()); + ASSERT_EQ(map.capacity(), hmap.capacity()); { uint32_t find_errors = 0; Impl::TestFind test_find(hmap, num_nodes, 1); test_find.testit(find_errors); - EXPECT_EQ( find_errors, 0u); + EXPECT_EQ(find_errors, 0u); } map_type mmap; @@ -297,35 +281,31 @@ void test_deep_copy( uint32_t num_nodes ) const_map_type cmap = mmap; - EXPECT_EQ( cmap.size(), num_nodes); + EXPECT_EQ(cmap.size(), num_nodes); { uint32_t find_errors = 0; Impl::TestFind test_find(cmap, num_nodes, 1); test_find.testit(find_errors); - EXPECT_EQ( find_errors, 0u); + EXPECT_EQ(find_errors, 0u); } - } -TEST_F( TEST_CATEGORY, UnorderedMap_insert) { - for (int i=0; i<500; ++i) { +TEST(TEST_CATEGORY, UnorderedMap_insert) { + for (int i = 0; i < 500; ++i) { test_insert(100000, 90000, 100, true); test_insert(100000, 90000, 100, false); } } -TEST_F( TEST_CATEGORY, UnorderedMap_failed_insert) { - for (int i=0; i<1000; ++i) - test_failed_insert(10000); +TEST(TEST_CATEGORY, UnorderedMap_failed_insert) { + for (int i = 0; i < 1000; ++i) test_failed_insert(10000); } -TEST_F( TEST_CATEGORY, UnorderedMap_deep_copy) { - for (int i=0; i<2; ++i) - test_deep_copy(10000); +TEST(TEST_CATEGORY, UnorderedMap_deep_copy) { + for (int i = 0; i < 2; ++i) test_deep_copy(10000); } -} // namespace Test - -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP +} // namespace Test +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestVector.hpp b/lib/kokkos/containers/unit_tests/TestVector.hpp index b766ae8718..4174a477c4 100644 --- a/lib/kokkos/containers/unit_tests/TestVector.hpp +++ b/lib/kokkos/containers/unit_tests/TestVector.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,85 +53,193 @@ namespace Test { namespace Impl { - template - struct test_vector_combinations - { - typedef test_vector_combinations self_type; - - typedef Scalar scalar_type; - typedef Device execution_space; - - Scalar reference; - Scalar result; - - template - Scalar run_me(unsigned int n){ - Vector a(n,1); - - - a.push_back(2); - a.resize(n+4); - a[n+1] = 3; - a[n+2] = 4; - a[n+3] = 5; - +template +struct test_vector_insert { + typedef Scalar scalar_type; + typedef Device execution_space; + + template + void run_test(Vector& a) { + int n = a.size(); + + auto it = a.begin(); + it += 15; + ASSERT_EQ(*it, scalar_type(1)); + + auto it_return = a.insert(it, scalar_type(3)); + ASSERT_EQ(a.size(), n + 1); + ASSERT_EQ(std::distance(it_return, a.begin() + 15), 0); + + it = a.begin(); + it += 17; +// Looks like some std::vector implementations do not have the restriction +// right on the overload taking three iterators, and thus the following call +// will hit that overload and then fail to compile. +#if defined(KOKKOS_COMPILER_INTEL) && (1700 > KOKKOS_COMPILER_INTEL) +// And at least GCC 4.8.4 doesn't implement vector insert correct for C++11 +// Return type is void ... +#if (__GNUC__ < 5) + a.insert(it, typename Vector::size_type(n + 5), scalar_type(5)); + it_return = a.begin() + 17; +#else + it_return = a.insert(it, typename Vector::size_type(n + 5), scalar_type(5)); +#endif +#else +#if (__GNUC__ < 5) + a.insert(it, n + 5, scalar_type(5)); + it_return = a.begin() + 17; +#else + it_return = a.insert(it, n + 5, scalar_type(5)); +#endif +#endif + + ASSERT_EQ(a.size(), n + 1 + n + 5); + ASSERT_EQ(std::distance(it_return, a.begin() + 17), 0); + + Vector b; + +// Looks like some std::vector implementations do not have the restriction +// right on the overload taking three iterators, and thus the following call +// will hit that overload and then fail to compile. +#if defined(KOKKOS_COMPILER_INTEL) && (1700 > KOKKOS_COMPILER_INTEL) + b.insert(b.begin(), typename Vector::size_type(7), 9); +#else + b.insert(b.begin(), 7, 9); +#endif + ASSERT_EQ(b.size(), 7); + ASSERT_EQ(b[0], scalar_type(9)); + + it = a.begin(); + it += 27 + n; +#if (__GNUC__ < 5) + a.insert(it, b.begin(), b.end()); + it_return = a.begin() + (27 + n); +#else + it_return = a.insert(it, b.begin(), b.end()); +#endif + ASSERT_EQ(a.size(), n + 1 + n + 5 + 7); + ASSERT_EQ(std::distance(it_return, a.begin() + 27 + n), 0); + + // Testing insert at end via all three function interfaces + a.insert(a.end(), 11); +#if defined(KOKKOS_COMPILER_INTEL) && (1700 > KOKKOS_COMPILER_INTEL) + a.insert(a.end(), typename Vector::size_type(2), 12); +#else + a.insert(a.end(), 2, 12); +#endif + a.insert(a.end(), b.begin(), b.end()); + } + + template + void check_test(Vector& a, int n) { + for (int i = 0; i < (int)a.size(); i++) { + if (i == 15) + ASSERT_EQ(a[i], scalar_type(3)); + else if (i > 16 && i < 16 + 6 + n) + ASSERT_EQ(a[i], scalar_type(5)); + else if (i > 26 + n && i < 34 + n) + ASSERT_EQ(a[i], scalar_type(9)); + else if (i == (int)a.size() - 10) + ASSERT_EQ(a[i], scalar_type(11)); + else if ((i == (int)a.size() - 9) || (i == (int)a.size() - 8)) + ASSERT_EQ(a[i], scalar_type(12)); + else if (i > (int)a.size() - 8) + ASSERT_EQ(a[i], scalar_type(9)); + else + ASSERT_EQ(a[i], scalar_type(1)); + } + } - Scalar temp1 = a[2]; - Scalar temp2 = a[n]; - Scalar temp3 = a[n+1]; + test_vector_insert(unsigned int size) { + { + std::vector a(size, scalar_type(1)); + run_test(a); + check_test(a, size); + } + { + Kokkos::vector a(size, scalar_type(1)); + a.sync_device(); + run_test(a); + a.sync_host(); + check_test(a, size); + } + { + Kokkos::vector a(size, scalar_type(1)); + a.sync_host(); + run_test(a); + check_test(a, size); + } + } +}; - a.assign(n+2,-1); +template +struct test_vector_combinations { + typedef test_vector_combinations self_type; - a[2] = temp1; - a[n] = temp2; - a[n+1] = temp3; + typedef Scalar scalar_type; + typedef Device execution_space; - Scalar test1 = 0; - for(unsigned int i=0; i + Scalar run_me(unsigned int n) { + Vector a(n, 1); - a.reserve(n+10); + a.push_back(2); + a.resize(n + 4); + a[n + 1] = 3; + a[n + 2] = 4; + a[n + 3] = 5; - Scalar test3 = 0; - for(unsigned int i=0; i >(size); - result = run_me >(size); - } + a.assign(n + 1, -2); + Scalar test2 = 0; + for (unsigned int i = 0; i < a.size(); i++) test2 += a[i]; - }; + a.reserve(n + 10); -} // namespace Impl + Scalar test3 = 0; + for (unsigned int i = 0; i < a.size(); i++) test3 += a[i]; + return (test1 * test2 + test3) * test2 + test1 * test3; + } + test_vector_combinations(unsigned int size) { + reference = run_me >(size); + result = run_me >(size); + } +}; +} // namespace Impl template -void test_vector_combinations(unsigned int size) -{ - Impl::test_vector_combinations test(size); - ASSERT_EQ( test.reference, test.result); +void test_vector_combinations(unsigned int size) { + Impl::test_vector_combinations test(size); + ASSERT_EQ(test.reference, test.result); } -TEST_F( TEST_CATEGORY, vector_combination) { - test_vector_combinations(10); - test_vector_combinations(3057); +TEST(TEST_CATEGORY, vector_combination) { + test_vector_combinations(10); + test_vector_combinations(3057); } -} // namespace Test +TEST(TEST_CATEGORY, vector_insert) { + Impl::test_vector_insert(3057); +} -#endif //KOKKOS_TEST_UNORDERED_MAP_HPP +} // namespace Test +#endif // KOKKOS_TEST_UNORDERED_MAP_HPP diff --git a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp index 2dd5c56cd9..6bac2ca9bd 100644 --- a/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp +++ b/lib/kokkos/containers/unit_tests/TestViewCtorPropEmbeddedDim.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,63 +56,58 @@ namespace Test { namespace { -template +template struct TestViewCtorProp_EmbeddedDim { + using ViewIntType = typename Kokkos::View; + using ViewDoubleType = typename Kokkos::View; - using ViewIntType = typename Kokkos::View< int**, ExecSpace >; - using ViewDoubleType = typename Kokkos::View< double*, ExecSpace >; + using DynRankViewIntType = typename Kokkos::DynRankView; + using DynRankViewDoubleType = typename Kokkos::DynRankView; - using DynRankViewIntType = typename Kokkos::DynRankView< int, ExecSpace >; - using DynRankViewDoubleType = typename Kokkos::DynRankView< double, ExecSpace >; - - // Cuda 7.0 has issues with using a lambda in parallel_for to initialize the view - replace with this functor - template < class ViewType > + // Cuda 7.0 has issues with using a lamda in parallel_for to initialize the + // view - replace with this functor + template struct Functor { - ViewType v; - Functor( const ViewType & v_ ) : v(v_) {} + Functor(const ViewType& v_) : v(v_) {} KOKKOS_INLINE_FUNCTION - void operator()( const int i ) const { - v(i) = i; - } - + void operator()(const int i) const { v(i) = i; } }; - - static void test_vcpt( const int N0, const int N1 ) - { - + static void test_vcpt(const int N0, const int N1) { // Create two views to test { - using VIT = typename TestViewCtorProp_EmbeddedDim::ViewIntType ; - using VDT = typename TestViewCtorProp_EmbeddedDim::ViewDoubleType ; + using VIT = typename TestViewCtorProp_EmbeddedDim::ViewIntType; + using VDT = typename TestViewCtorProp_EmbeddedDim::ViewDoubleType; VIT vi1("vi1", N0, N1); VDT vd1("vd1", N0); - // TEST: Test for common type between two views, one with type double, other with type int - // Deduce common value_type and construct a view with that type + // TEST: Test for common type between two views, one with type double, + // other with type int Deduce common value_type and construct a view with + // that type { // Two views auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1, vd1); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, double >::value) , true ) ; - #if 0 + ASSERT_EQ((std::is_same::value), true); +#if 0 // debug output for ( int i = 0; i < N0*N1; ++i ) { printf(" Output check: hcv1(%d) = %lf\n ", i, hcv1(i) ); @@ -126,91 +122,92 @@ struct TestViewCtorProp_EmbeddedDim { printf("WRONG common value_type\n"); } // end debug output - #endif +#endif } { // Single view auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ; + ASSERT_EQ((std::is_same::value), true); } - } // Create two dynamic rank views to test { - using VIT = typename TestViewCtorProp_EmbeddedDim::DynRankViewIntType ; - using VDT = typename TestViewCtorProp_EmbeddedDim::DynRankViewDoubleType ; + using VIT = typename TestViewCtorProp_EmbeddedDim::DynRankViewIntType; + using VDT = typename TestViewCtorProp_EmbeddedDim::DynRankViewDoubleType; VIT vi1("vi1", N0, N1); VDT vd1("vd1", N0); - // TEST: Test for common type between two views, one with type double, other with type int - // Deduce common value_type and construct a view with that type + // TEST: Test for common type between two views, one with type double, + // other with type int Deduce common value_type and construct a view with + // that type { // Two views - auto view_alloc_arg = Kokkos::common_view_alloc_prop( vi1, vd1 ); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; - - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1, vd1); + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, double >::value) , true ) ; + ASSERT_EQ((std::is_same::value), true); } { // Single views - auto view_alloc_arg = Kokkos::common_view_alloc_prop( vi1 ); - typedef typename decltype( view_alloc_arg )::value_type CommonViewValueType; - typedef typename Kokkos::View< CommonViewValueType*, ExecSpace > CVT; - typedef typename CVT::HostMirror HostCVT; + auto view_alloc_arg = Kokkos::common_view_alloc_prop(vi1); + typedef + typename decltype(view_alloc_arg)::value_type CommonViewValueType; + typedef typename Kokkos::View CVT; + typedef typename CVT::HostMirror HostCVT; - // Construct View using the common type; for case of specialization, an 'embedded_dim' would be stored by view_alloc_arg - CVT cv1( Kokkos::view_alloc( "cv1", view_alloc_arg ), N0*N1 ); + // Construct View using the common type; for case of specialization, an + // 'embedded_dim' would be stored by view_alloc_arg + CVT cv1(Kokkos::view_alloc("cv1", view_alloc_arg), N0 * N1); - Kokkos::parallel_for( Kokkos::RangePolicy< ExecSpace >(0, N0*N1), - Functor(cv1) - ); + Kokkos::parallel_for(Kokkos::RangePolicy(0, N0 * N1), + Functor(cv1)); - HostCVT hcv1 = Kokkos::create_mirror_view( cv1 ); - Kokkos::deep_copy( hcv1, cv1 ); + HostCVT hcv1 = Kokkos::create_mirror_view(cv1); + Kokkos::deep_copy(hcv1, cv1); - ASSERT_EQ( (std::is_same< CommonViewValueType, int>::value) , true ) ; + ASSERT_EQ((std::is_same::value), true); } } + } // end test_vcpt - } // end test_vcpt - -}; // end struct +}; // end struct -} // namespace +} // namespace -TEST_F( TEST_CATEGORY, viewctorprop_embedded_dim ) { - TestViewCtorProp_EmbeddedDim< TEST_EXECSPACE >::test_vcpt( 2, 3 ); +TEST(TEST_CATEGORY, viewctorprop_embedded_dim) { + TestViewCtorProp_EmbeddedDim::test_vcpt(2, 3); } -} // namespace Test +} // namespace Test diff --git a/lib/kokkos/containers/unit_tests/UnitTestMain.cpp b/lib/kokkos/containers/unit_tests/UnitTestMain.cpp index 508b43efd8..e245aad35f 100644 --- a/lib/kokkos/containers/unit_tests/UnitTestMain.cpp +++ b/lib/kokkos/containers/unit_tests/UnitTestMain.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,14 +43,12 @@ */ #include -#include #include int main(int argc, char *argv[]) { - Kokkos::initialize(argc,argv); - ::testing::InitGoogleTest(&argc,argv); + Kokkos::initialize(argc, argv); + ::testing::InitGoogleTest(&argc, argv); int result = RUN_ALL_TESTS(); Kokkos::finalize(); return result; } - diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp index 5f7bc684e6..5306ab3883 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp index 3e0d142480..50935d7a34 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_CUDA_HPP #define KOKKOS_TEST_CUDA_HPP -#include - -namespace Test { - -class cuda : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY cuda #define TEST_EXECSPACE Kokkos::Cuda diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp index 1930293c3a..5641966db4 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp index 3d381b3fb6..609c8b41a5 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp index 08d5b3957a..66d2d17e8b 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp index a655491e81..19e248dd93 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp index 1986fd7e92..9eccb05a25 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp index 22d8d15e03..806a3c6ecc 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp index 546f6d603a..b2e851d099 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp index 9bd1bbab2c..10b63d037d 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp index b15abcf525..9c93da9c50 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp index 881b20b575..b204e68977 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp index cf0f2012dc..408d0c76fc 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp index 7130195839..c865deb0b2 100644 --- a/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/cuda/TestCuda_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp index cec24e00c7..179cfcc7b4 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp index 358b42d1aa..64fc7c0757 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_HPX_HPP #define KOKKOS_TEST_HPX_HPP -#include - -namespace Test { - -class hpx : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY hpx #define TEST_EXECSPACE Kokkos::Experimental::HPX diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp index 80af9dc33a..368cdde95c 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp index 95d49c8acf..778bd891d6 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp index 72e0bc6616..0bb77a266d 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp index 5a104f0de2..6594cb3213 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp index 718b322684..c1efc778a6 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp index ea819ae343..3f68c6d07f 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp index 4d3684923f..1719300228 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp index 6a871cc121..8f9eb05918 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp index fbb70a762b..4f513efb0f 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp index 7e7aad309f..517135290a 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp index 5fb3664197..d42cef4b28 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp index fb9c263c83..de2e96be73 100644 --- a/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/hpx/TestHPX_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp index 2f3a52787d..db11017159 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp index 150173e4bf..a0169d1702 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_OPENMP_HPP #define KOKKOS_TEST_OPENMP_HPP -#include - -namespace Test { - -class openmp : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY openmp #define TEST_EXECSPACE Kokkos::OpenMP diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp index fd6b9ae707..ed4eb23a8b 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp index 066d8f9194..637be64dfa 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp index f44e320eba..01b57a1690 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp index 154243aec9..7d742eaeed 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp index 7d9ead910f..75b616f168 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp index d05bf163bf..1f00f18532 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp index 169dae3212..98531ff212 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp index 3adfcd8409..c49577f75d 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp index 486a51a0b9..d8ab7b6b21 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp index 32dc22ec93..c3db0c0d88 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp index 006caba816..7ac49f24fb 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp index dbbf14cb5b..b9ae5d80ed 100644 --- a/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/openmp/TestOpenMP_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp index 2c8657e464..c72077eb4c 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp index d520bbc5a7..d37cd05db6 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_ROCM_HPP #define KOKKOS_TEST_ROCM_HPP -#include - -namespace Test { - -class rocm : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY rocm #define TEST_EXECSPACE Kokkos::Experimental::ROCm diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp index f60c6ade44..e9820395ba 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp index 80bfe06153..7a3dd65f0e 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp index b42ce07e8f..3963dd9c9c 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp index 0f47b800c6..b9a4582622 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp index 5540eb2d20..285ed916c4 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp index 2c7a26c7fe..2af2f79a16 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp index cc4a07ddbd..f7000bc99e 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp index be83d4ef50..bb1e04c536 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp index f6b2f9ef40..7b8172fabd 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp index e9073b6bb5..1759797487 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp index dd472270e7..e95680445b 100644 --- a/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/rocm/TestROCm_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp index 03edd30c34..322e88a6af 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp index 858b669286..2aa09a315a 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_SERIAL_HPP #define KOKKOS_TEST_SERIAL_HPP -#include - -namespace Test { - -class serial : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY serial #define TEST_EXECSPACE Kokkos::Serial diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp index 0dac8eba87..c1646ed13b 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp index 1a5874e7fa..e8f577c6ac 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp index df802bfe68..7db8983c1b 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp index 84e5b452c4..a3a745efb5 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp index 34f4002db2..6624e3aa07 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp index 326853f33a..280302275f 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp index fadd748efb..5f8caf7c3f 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_OffsetView.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,6 +42,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp index ee04d35584..3f102e5cbc 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp index 2d10ee70d2..64f09e76e5 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp index e78667e8aa..a72be8e2fc 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp index bf98055622..3826dab1d7 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp index 143b1f1c2d..1251808bed 100644 --- a/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/serial/TestSerial_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp index 0dfe69fee2..ec93bb121c 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_BitSet.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp index c4d0ed6da2..74a2b0da36 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,21 +45,6 @@ #ifndef KOKKOS_TEST_THREADS_HPP #define KOKKOS_TEST_THREADS_HPP -#include - -namespace Test { - -class threads : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test - #define TEST_CATEGORY threads #define TEST_EXECSPACE Kokkos::Threads diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp index 0ddafcd6fd..f6967bf0d4 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DualView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp index 0030673785..b015683bb9 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_generic.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp index db39db38b3..dea56c408b 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank12345.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp index 1d1f94d6cf..17a289b506 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynRankViewAPI_rank67.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp index 61616a5132..499321dbbe 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_DynamicView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp index a64c3f4082..513fdc4af6 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_ErrorReporter.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp index d1eaa265e3..717967b2ef 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_OffsetView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp index 6c7138058d..fbb37606ea 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_ScatterView.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp index f6a1204dd3..29117c4ef6 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_StaticCrsGraph.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp index 2f3aeedae0..9a06288de4 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_UnorderedMap.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp index a497d43772..33e8b26c8e 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_Vector.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp b/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp index 89f85dca56..567b224195 100644 --- a/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp +++ b/lib/kokkos/containers/unit_tests/threads/TestThreads_ViewCtorPropEmbeddedDim.cpp @@ -3,10 +3,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -24,10 +25,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,6 +43,5 @@ //@HEADER */ -#include -#include - +#include +#include diff --git a/lib/kokkos/core/CMakeLists.txt b/lib/kokkos/core/CMakeLists.txt index 93db0d2ecf..8df72dfc90 100644 --- a/lib/kokkos/core/CMakeLists.txt +++ b/lib/kokkos/core/CMakeLists.txt @@ -1,13 +1,12 @@ - - -TRIBITS_SUBPACKAGE(Core) - -IF(KOKKOS_HAS_TRILINOS) - ADD_SUBDIRECTORY(src) -ENDIF() - -TRIBITS_ADD_TEST_DIRECTORIES(unit_test) -TRIBITS_ADD_TEST_DIRECTORIES(perf_test) - -TRIBITS_SUBPACKAGE_POSTPROCESS() - + + +KOKKOS_SUBPACKAGE(Core) + +ADD_SUBDIRECTORY(src) + +KOKKOS_ADD_TEST_DIRECTORIES(unit_test) +KOKKOS_ADD_TEST_DIRECTORIES(perf_test) + +KOKKOS_SUBPACKAGE_POSTPROCESS() + + diff --git a/lib/kokkos/core/cmake/KokkosCore_config.h.in b/lib/kokkos/core/cmake/KokkosCore_config.h.in index b2c80207d4..f430c2b5f6 100644 --- a/lib/kokkos/core/cmake/KokkosCore_config.h.in +++ b/lib/kokkos/core/cmake/KokkosCore_config.h.in @@ -13,8 +13,7 @@ #cmakedefine KOKKOS_ENABLE_CUDA #cmakedefine KOKKOS_ENABLE_OPENMP -#cmakedefine KOKKOS_ENABLE_PTHREAD -#cmakedefine KOKKOS_ENABLE_QTHREADS +#cmakedefine KOKKOS_ENABLE_THREADS #cmakedefine KOKKOS_ENABLE_SERIAL #cmakedefine KOKKOS_ENABLE_Winthread diff --git a/lib/kokkos/core/perf_test/CMakeLists.txt b/lib/kokkos/core/perf_test/CMakeLists.txt index d92462a357..79567835ee 100644 --- a/lib/kokkos/core/perf_test/CMakeLists.txt +++ b/lib/kokkos/core/perf_test/CMakeLists.txt @@ -1,59 +1,71 @@ -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) +#INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +#INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) -IF(NOT KOKKOS_HAS_TRILINOS) - IF(KOKKOS_SEPARATE_LIBS) - set(TEST_LINK_TARGETS kokkoscore) - ELSE() - set(TEST_LINK_TARGETS kokkos) - ENDIF() -ENDIF() # warning: PerfTest_CustomReduction.cpp uses # ../../algorithms/src/Kokkos_Random.hpp # we'll just allow it to be included, but note # that in TriBITS KokkosAlgorithms can be disabled... -INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms/src") +#INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms/src") SET(SOURCES PerfTestMain.cpp PerfTestGramSchmidt.cpp PerfTestHexGrad.cpp PerfTest_CustomReduction.cpp + PerfTest_ExecSpacePartitioning.cpp + PerfTest_ViewCopy_a123.cpp + PerfTest_ViewCopy_b123.cpp + PerfTest_ViewCopy_c123.cpp + PerfTest_ViewCopy_d123.cpp + PerfTest_ViewCopy_a45.cpp + PerfTest_ViewCopy_b45.cpp + PerfTest_ViewCopy_c45.cpp + PerfTest_ViewCopy_d45.cpp + PerfTest_ViewCopy_a6.cpp + PerfTest_ViewCopy_b6.cpp + PerfTest_ViewCopy_c6.cpp + PerfTest_ViewCopy_d6.cpp + PerfTest_ViewCopy_a7.cpp + PerfTest_ViewCopy_b7.cpp + PerfTest_ViewCopy_c7.cpp + PerfTest_ViewCopy_d7.cpp + PerfTest_ViewCopy_a8.cpp + PerfTest_ViewCopy_b8.cpp + PerfTest_ViewCopy_c8.cpp + PerfTest_ViewCopy_d8.cpp + PerfTest_ViewAllocate.cpp + PerfTest_ViewFill_123.cpp + PerfTest_ViewFill_45.cpp + PerfTest_ViewFill_6.cpp + PerfTest_ViewFill_7.cpp + PerfTest_ViewFill_8.cpp + PerfTest_ViewResize_123.cpp + PerfTest_ViewResize_45.cpp + PerfTest_ViewResize_6.cpp + PerfTest_ViewResize_7.cpp + PerfTest_ViewResize_8.cpp ) # Per #374, we always want to build this test, but we only want to run # it as a PERFORMANCE test. That's why we separate building the test # from running the test. -TRIBITS_ADD_EXECUTABLE( +#leave these as basic includes for now +#I don't need anything transitive +KOKKOS_INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/../../algorithms/src") +KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) +KOKKOS_INCLUDE_DIRECTORIES(REQUIRED_DURING_INSTALLATION_TESTING ${CMAKE_CURRENT_SOURCE_DIR}) + +KOKKOS_ADD_EXECUTABLE_AND_TEST( PerfTestExec SOURCES ${SOURCES} - COMM serial mpi - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) - -TRIBITS_ADD_TEST( - PerfTest - NAME PerfTestExec - COMM serial mpi - NUM_MPI_PROCS 1 CATEGORIES PERFORMANCE - FAIL_REGULAR_EXPRESSION " FAILED " - ) +) -TRIBITS_ADD_EXECUTABLE( - PerformanceTest_TaskDAG +KOKKOS_ADD_EXECUTABLE_AND_TEST( + PerformanceTest_TaskDag SOURCES test_taskdag.cpp - COMM serial mpi - TESTONLYLIBS kokkos_gtest ${TEST_LINK_TARGETS} - ) - -TRIBITS_ADD_TEST( - PerformanceTest_TaskDAG - NAME PerformanceTest_TaskDAG - COMM serial mpi - NUM_MPI_PROCS 1 CATEGORIES PERFORMANCE - ) +) diff --git a/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp b/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp index ff9bf5a91b..a5a376565d 100644 --- a/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp +++ b/lib/kokkos/core/perf_test/PerfTestBlasKernels.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -48,217 +49,186 @@ namespace Kokkos { -template< class ConstVectorType , - class Device = typename ConstVectorType::execution_space > -struct Dot ; +template +struct Dot; -template< class ConstVectorType , - class Device = typename ConstVectorType::execution_space > -struct DotSingle ; +template +struct DotSingle; -template< class ConstScalarType , - class VectorType , - class Device = typename VectorType::execution_space > -struct Scale ; +template +struct Scale; -template< class ConstScalarType , - class ConstVectorType , - class VectorType , - class Device = typename VectorType::execution_space > -struct AXPBY ; +template +struct AXPBY; /** \brief Y = alpha * X + beta * Y */ -template< class ConstScalarType , - class ConstVectorType , - class VectorType > -void axpby( const ConstScalarType & alpha , - const ConstVectorType & X , - const ConstScalarType & beta , - const VectorType & Y ) -{ - typedef AXPBY< ConstScalarType , ConstVectorType , VectorType > functor ; - - parallel_for( Y.extent(0) , functor( alpha , X , beta , Y ) ); +template +void axpby(const ConstScalarType& alpha, const ConstVectorType& X, + const ConstScalarType& beta, const VectorType& Y) { + typedef AXPBY functor; + + parallel_for(Y.extent(0), functor(alpha, X, beta, Y)); } /** \brief Y *= alpha */ -template< class ConstScalarType , - class VectorType > -void scale( const ConstScalarType & alpha , const VectorType & Y ) -{ - typedef Scale< ConstScalarType , VectorType > functor ; +template +void scale(const ConstScalarType& alpha, const VectorType& Y) { + typedef Scale functor; - parallel_for( Y.extent(0) , functor( alpha , Y ) ); + parallel_for(Y.extent(0), functor(alpha, Y)); } -template< class ConstVectorType , - class Finalize > -void dot( const ConstVectorType & X , - const ConstVectorType & Y , - const Finalize & finalize ) -{ - typedef Dot< ConstVectorType > functor ; +template +void dot(const ConstVectorType& X, const ConstVectorType& Y, + const Finalize& finalize) { + typedef Dot functor; - parallel_reduce( X.extent(0) , functor( X , Y ) , finalize ); + parallel_reduce(X.extent(0), functor(X, Y), finalize); } -template< class ConstVectorType , - class Finalize > -void dot( const ConstVectorType & X , - const Finalize & finalize ) -{ - typedef DotSingle< ConstVectorType > functor ; +template +void dot(const ConstVectorType& X, const Finalize& finalize) { + typedef DotSingle functor; - parallel_reduce( X.extent(0) , functor( X ) , finalize ); + parallel_reduce(X.extent(0), functor(X), finalize); } } /* namespace Kokkos */ - //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -template< class Type , class Device > -struct Dot -{ - typedef typename Device::execution_space execution_space ; - - static_assert( static_cast(Type::Rank) == static_cast(1), - "Dot static_assert Fail: Rank != 1"); +template +struct Dot { + typedef typename Device::execution_space execution_space; + static_assert(static_cast(Type::Rank) == static_cast(1), + "Dot static_assert Fail: Rank != 1"); - typedef double value_type ; + typedef double value_type; #if 1 - typename Type::const_type X ; - typename Type::const_type Y ; + typename Type::const_type X; + typename Type::const_type Y; #else - Type X ; - Type Y ; + Type X; + Type Y; #endif - Dot( const Type & arg_x , const Type & arg_y ) - : X(arg_x) , Y(arg_y) { } + Dot(const Type& arg_x, const Type& arg_y) : X(arg_x), Y(arg_y) {} KOKKOS_INLINE_FUNCTION - void operator()( int i , value_type & update ) const - { update += X[i] * Y[i]; } + void operator()(int i, value_type& update) const { update += X[i] * Y[i]; } KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & source ) - { update += source; } + static void join(volatile value_type& update, + const volatile value_type& source) { + update += source; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } }; -template< class Type , class Device > -struct DotSingle -{ - typedef typename Device::execution_space execution_space ; +template +struct DotSingle { + typedef typename Device::execution_space execution_space; - static_assert( static_cast(Type::Rank) == static_cast(1), - "DotSingle static_assert Fail: Rank != 1"); + static_assert(static_cast(Type::Rank) == static_cast(1), + "DotSingle static_assert Fail: Rank != 1"); - typedef double value_type ; + typedef double value_type; #if 1 - typename Type::const_type X ; + typename Type::const_type X; #else - Type X ; + Type X; #endif - DotSingle( const Type & arg_x ) : X(arg_x) {} + DotSingle(const Type& arg_x) : X(arg_x) {} KOKKOS_INLINE_FUNCTION - void operator()( int i , value_type & update ) const - { - const typename Type::value_type & x = X[i]; update += x * x ; - } + void operator()(int i, value_type& update) const { + const typename Type::value_type& x = X[i]; + update += x * x; + } KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - const volatile value_type & source ) - { update += source; } + static void join(volatile value_type& update, + const volatile value_type& source) { + update += source; + } KOKKOS_INLINE_FUNCTION - static void init( value_type & update ) - { update = 0 ; } + static void init(value_type& update) { update = 0; } }; +template +struct Scale { + typedef typename Device::execution_space execution_space; -template< class ScalarType , class VectorType , class Device> -struct Scale -{ - typedef typename Device::execution_space execution_space ; + static_assert(static_cast(ScalarType::Rank) == + static_cast(0), + "Scale static_assert Fail: ScalarType::Rank != 0"); - static_assert( static_cast(ScalarType::Rank) == static_cast(0), - "Scale static_assert Fail: ScalarType::Rank != 0"); - - static_assert( static_cast(VectorType::Rank) == static_cast(1), - "Scale static_assert Fail: VectorType::Rank != 1"); + static_assert(static_cast(VectorType::Rank) == + static_cast(1), + "Scale static_assert Fail: VectorType::Rank != 1"); #if 1 - typename ScalarType::const_type alpha ; + typename ScalarType::const_type alpha; #else - ScalarType alpha ; + ScalarType alpha; #endif - VectorType Y ; + VectorType Y; - Scale( const ScalarType & arg_alpha , const VectorType & arg_Y ) - : alpha( arg_alpha ), Y( arg_Y ) {} + Scale(const ScalarType& arg_alpha, const VectorType& arg_Y) + : alpha(arg_alpha), Y(arg_Y) {} KOKKOS_INLINE_FUNCTION - void operator()( int i ) const - { - Y[i] *= alpha() ; - } + void operator()(int i) const { Y[i] *= alpha(); } }; - -template< class ScalarType , - class ConstVectorType , - class VectorType, +template -struct AXPBY -{ - typedef typename Device::execution_space execution_space ; +struct AXPBY { + typedef typename Device::execution_space execution_space; - static_assert( static_cast(ScalarType::Rank) == static_cast(0), - "AXPBY static_assert Fail: ScalarType::Rank != 0"); + static_assert(static_cast(ScalarType::Rank) == + static_cast(0), + "AXPBY static_assert Fail: ScalarType::Rank != 0"); - static_assert( static_cast(ConstVectorType::Rank) == static_cast(1), - "AXPBY static_assert Fail: ConstVectorType::Rank != 1"); + static_assert(static_cast(ConstVectorType::Rank) == + static_cast(1), + "AXPBY static_assert Fail: ConstVectorType::Rank != 1"); - static_assert( static_cast(VectorType::Rank) == static_cast(1), - "AXPBY static_assert Fail: VectorType::Rank != 1"); + static_assert(static_cast(VectorType::Rank) == + static_cast(1), + "AXPBY static_assert Fail: VectorType::Rank != 1"); #if 1 - typename ScalarType::const_type alpha , beta ; - typename ConstVectorType::const_type X ; + typename ScalarType::const_type alpha, beta; + typename ConstVectorType::const_type X; #else - ScalarType alpha , beta ; - ConstVectorType X ; + ScalarType alpha, beta; + ConstVectorType X; #endif - VectorType Y ; + VectorType Y; - AXPBY( const ScalarType & arg_alpha , - const ConstVectorType & arg_X , - const ScalarType & arg_beta , - const VectorType & arg_Y ) - : alpha( arg_alpha ), beta( arg_beta ), X( arg_X ), Y( arg_Y ) {} + AXPBY(const ScalarType& arg_alpha, const ConstVectorType& arg_X, + const ScalarType& arg_beta, const VectorType& arg_Y) + : alpha(arg_alpha), beta(arg_beta), X(arg_X), Y(arg_Y) {} KOKKOS_INLINE_FUNCTION - void operator()( int i ) const - { - Y[i] = alpha() * X[i] + beta() * Y[i] ; - } + void operator()(int i) const { Y[i] = alpha() * X[i] + beta() * Y[i]; } }; } /* namespace Kokkos */ diff --git a/lib/kokkos/core/perf_test/PerfTestDriver.hpp b/lib/kokkos/core/perf_test/PerfTestDriver.hpp index 5367f2542e..95d5128abf 100644 --- a/lib/kokkos/core/perf_test/PerfTestDriver.hpp +++ b/lib/kokkos/core/perf_test/PerfTestDriver.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -60,244 +61,262 @@ namespace Test { enum { NUMBER_OF_TRIALS = 5 }; -template< class DeviceType , class LayoutType > -void run_test_mdrange( int exp_beg , int exp_end, const char deviceTypeName[], int range_offset = 0, int tile_offset = 0 ) +template +void run_test_mdrange(int exp_beg, int exp_end, const char deviceTypeName[], + int range_offset = 0, int tile_offset = 0) // exp_beg = 6 => 2^6 = 64 is starting range length { #define MDRANGE_PERFORMANCE_OUTPUT_VERBOSE 0 - std::string label_mdrange ; - label_mdrange.append( "\"MDRange< double , " ); - label_mdrange.append( deviceTypeName ); - label_mdrange.append( " >\"" ); - - std::string label_range_col2 ; - label_range_col2.append( "\"RangeColTwo< double , " ); - label_range_col2.append( deviceTypeName ); - label_range_col2.append( " >\"" ); - - std::string label_range_col_all ; - label_range_col_all.append( "\"RangeColAll< double , " ); - label_range_col_all.append( deviceTypeName ); - label_range_col_all.append( " >\"" ); - - if ( std::is_same::value) { - std::cout << "--------------------------------------------------------------\n" - << "Performance tests for MDRange Layout Right" - << "\n--------------------------------------------------------------" << std::endl; + std::string label_mdrange; + label_mdrange.append("\"MDRange< double , "); + label_mdrange.append(deviceTypeName); + label_mdrange.append(" >\""); + + std::string label_range_col2; + label_range_col2.append("\"RangeColTwo< double , "); + label_range_col2.append(deviceTypeName); + label_range_col2.append(" >\""); + + std::string label_range_col_all; + label_range_col_all.append("\"RangeColAll< double , "); + label_range_col_all.append(deviceTypeName); + label_range_col_all.append(" >\""); + + if (std::is_same::value) { + std::cout + << "--------------------------------------------------------------\n" + << "Performance tests for MDRange Layout Right" + << "\n--------------------------------------------------------------" + << std::endl; } else { - std::cout << "--------------------------------------------------------------\n" - << "Performance tests for MDRange Layout Left" - << "\n--------------------------------------------------------------" << std::endl; + std::cout + << "--------------------------------------------------------------\n" + << "Performance tests for MDRange Layout Left" + << "\n--------------------------------------------------------------" + << std::endl; } + for (int i = exp_beg; i < exp_end; ++i) { + const int range_length = (1 << i) + range_offset; - for (int i = exp_beg ; i < exp_end ; ++i) { - const int range_length = (1<= min_bnd ) { - int tmid = min_bnd; - while ( tmid < tfast ) { - t0 = min_bnd; - t1 = tmid; - t2 = tfast; - int t2_rev = min_bnd; - int t1_rev = tmid; - int t0_rev = tfast; + while (tfast >= min_bnd) { + int tmid = min_bnd; + while (tmid < tfast) { + t0 = min_bnd; + t1 = tmid; + t2 = tfast; + int t2_rev = min_bnd; + int t1_rev = tmid; + int t0_rev = tfast; #if defined(KOKKOS_ENABLE_CUDA) - //Note: Product of tile sizes must be < 1024 for Cuda - if ( t0*t1*t2 >= 1024 ) { - printf(" Exceeded Cuda tile limits; onto next range set\n\n"); - break; - } + // Note: Product of tile sizes must be < 1024 for Cuda + if (t0 * t1 * t2 >= 1024) { + printf(" Exceeded Cuda tile limits; onto next range set\n\n"); + break; + } #endif - // Run 1 with tiles LayoutRight style - double seconds_1 = 0; - { seconds_1 = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, t0, t1, t2) ; } + // Run 1 with tiles LayoutRight style + double seconds_1 = 0; + { + seconds_1 = + MultiDimRangePerf3D::test_multi_index(range_length, + range_length, + range_length, + t0, t1, t2); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << label_mdrange - << " , " << t0 << " , " << t1 << " , " << t2 - << " , " << seconds_1 - << std::endl ; + std::cout << label_mdrange << " , " << t0 << " , " << t1 << " , " + << t2 << " , " << seconds_1 << std::endl; #endif - if ( counter == 1 ) { - seconds_min = seconds_1; - t0_min = t0; - t1_min = t1; - t2_min = t2; - } - else { - if ( seconds_1 < seconds_min ) - { - seconds_min = seconds_1; - t0_min = t0; - t1_min = t1; - t2_min = t2; + if (counter == 1) { + seconds_min = seconds_1; + t0_min = t0; + t1_min = t1; + t2_min = t2; + } else { + if (seconds_1 < seconds_min) { + seconds_min = seconds_1; + t0_min = t0; + t1_min = t1; + t2_min = t2; + } } - } - // Run 2 with tiles LayoutLeft style - reverse order of tile dims - double seconds_1rev = 0; - { seconds_1rev = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, t0_rev, t1_rev, t2_rev) ; } + // Run 2 with tiles LayoutLeft style - reverse order of tile dims + double seconds_1rev = 0; + { + seconds_1rev = + MultiDimRangePerf3D::test_multi_index(range_length, + range_length, + range_length, + t0_rev, + t1_rev, + t2_rev); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << label_mdrange - << " , " << t0_rev << " , " << t1_rev << " , " << t2_rev - << " , " << seconds_1rev - << std::endl ; + std::cout << label_mdrange << " , " << t0_rev << " , " << t1_rev + << " , " << t2_rev << " , " << seconds_1rev << std::endl; #endif - if ( seconds_1rev < seconds_min ) - { - seconds_min = seconds_1rev; - t0_min = t0_rev; - t1_min = t1_rev; - t2_min = t2_rev; - } + if (seconds_1rev < seconds_min) { + seconds_min = seconds_1rev; + t0_min = t0_rev; + t1_min = t1_rev; + t2_min = t2_rev; + } - ++counter; - tmid <<= 1; - } //end inner while - tfast >>=1; - } //end outer while - - std::cout << "\n" - << "--------------------------------------------------------------\n" - << label_mdrange - << "\n Min values " - << "\n Range length per dim (3D): " << range_length - << "\n TileDims: " << t0_min << " , " << t1_min << " , " << t2_min - << "\n Min time: " << seconds_min - << "\n---------------------------------------------------------------" - << std::endl ; - } //end scope + ++counter; + tmid <<= 1; + } // end inner while + tfast >>= 1; + } // end outer while + + std::cout + << "\n" + << "--------------------------------------------------------------\n" + << label_mdrange << "\n Min values " + << "\n Range length per dim (3D): " << range_length + << "\n TileDims: " << t0_min << " , " << t1_min << " , " << t2_min + << "\n Min time: " << seconds_min + << "\n---------------------------------------------------------------" + << std::endl; + } // end scope #if !defined(KOKKOS_ENABLE_CUDA) - double seconds_min_c = 0.0; - int t0c_min = 0, t1c_min = 0, t2c_min = 0; - int counter = 1; - { - int min_bnd = 8; - // Test 1_c: MDRange with 0 for 'inner' tile dim; this case will utilize the full span in that direction, should be similar to Collapse<2> - if ( std::is_same::value ) { - for ( unsigned int T0 = min_bnd; T0 < static_cast(range_length); T0<<=1 ) { - for ( unsigned int T1 = min_bnd; T1 < static_cast(range_length); T1<<=1 ) { - double seconds_c = 0; - { seconds_c = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, T0, T1, 0) ; } + double seconds_min_c = 0.0; + int t0c_min = 0, t1c_min = 0, t2c_min = 0; + int counter = 1; + { + int min_bnd = 8; + // Test 1_c: MDRange with 0 for 'inner' tile dim; this case will utilize + // the full span in that direction, should be similar to Collapse<2> + if (std::is_same::value) { + for (unsigned int T0 = min_bnd; + T0 < static_cast(range_length); T0 <<= 1) { + for (unsigned int T1 = min_bnd; + T1 < static_cast(range_length); T1 <<= 1) { + double seconds_c = 0; + { + seconds_c = MultiDimRangePerf3D:: + test_multi_index(range_length, range_length, range_length, T0, + T1, 0); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << " MDRange LR with '0' tile - collapse-like \n" - << label_mdrange - << " , " << T0 << " , " << T1 << " , " << range_length - << " , " << seconds_c - << std::endl ; + std::cout << " MDRange LR with '0' tile - collapse-like \n" + << label_mdrange << " , " << T0 << " , " << T1 << " , " + << range_length << " , " << seconds_c << std::endl; #endif - t2c_min = range_length; - if ( counter == 1 ) { - seconds_min_c = seconds_c; - t0c_min = T0; - t1c_min = T1; - } - else { - if ( seconds_c < seconds_min_c ) - { - seconds_min_c = seconds_c; - t0c_min = T0; - t1c_min = T1; + t2c_min = range_length; + if (counter == 1) { + seconds_min_c = seconds_c; + t0c_min = T0; + t1c_min = T1; + } else { + if (seconds_c < seconds_min_c) { + seconds_min_c = seconds_c; + t0c_min = T0; + t1c_min = T1; + } } + ++counter; } - ++counter; } - } - } - else { - for ( unsigned int T1 = min_bnd; T1 <= static_cast(range_length); T1<<=1 ) { - for ( unsigned int T2 = min_bnd; T2 <= static_cast(range_length); T2<<=1 ) { - double seconds_c = 0; - { seconds_c = MultiDimRangePerf3D< DeviceType , double , LayoutType >::test_multi_index(range_length,range_length,range_length, 0, T1, T2) ; } + } else { + for (unsigned int T1 = min_bnd; + T1 <= static_cast(range_length); T1 <<= 1) { + for (unsigned int T2 = min_bnd; + T2 <= static_cast(range_length); T2 <<= 1) { + double seconds_c = 0; + { + seconds_c = MultiDimRangePerf3D:: + test_multi_index(range_length, range_length, range_length, 0, + T1, T2); + } #if MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - std::cout << " MDRange LL with '0' tile - collapse-like \n" - << label_mdrange - << " , " < style: " - << "\n Min values " - << "\n Range length per dim (3D): " << range_length - << "\n TileDims: " << t0c_min << " , " << t1c_min << " , " << t2c_min - << "\n Min time: " << seconds_min_c - << "\n---------------------------------------------------------------" - << std::endl ; - } //end scope test 2 + std::cout + // << + // "--------------------------------------------------------------\n" + << label_mdrange << " Collapse<2> style: " + << "\n Min values " + << "\n Range length per dim (3D): " << range_length + << "\n TileDims: " << t0c_min << " , " << t1c_min << " , " << t2c_min + << "\n Min time: " << seconds_min_c + << "\n---------------------------------------------------------------" + << std::endl; + } // end scope test 2 #endif - // Test 2: RangePolicy Collapse2 style double seconds_2 = 0; - { seconds_2 = RangePolicyCollapseTwo< DeviceType , double , LayoutType >::test_index_collapse_two(range_length,range_length,range_length) ; } - std::cout << label_range_col2 - << " , " << range_length - << " , " << seconds_2 - << std::endl ; - + { + seconds_2 = RangePolicyCollapseTwo:: + test_index_collapse_two(range_length, range_length, range_length); + } + std::cout << label_range_col2 << " , " << range_length << " , " << seconds_2 + << std::endl; // Test 3: RangePolicy Collapse all style - not necessary, always slow /* double seconds_3 = 0; - { seconds_3 = RangePolicyCollapseAll< DeviceType , double , LayoutType >::test_collapse_all(range_length,range_length,range_length) ; } - std::cout << label_range_col_all + { seconds_3 = RangePolicyCollapseAll< DeviceType , double , LayoutType + >::test_collapse_all(range_length,range_length,range_length) ; } std::cout + << label_range_col_all << " , " << range_length << " , " << seconds_3 << "\n---------------------------------------------------------------" @@ -306,97 +325,105 @@ void run_test_mdrange( int exp_beg , int exp_end, const char deviceTypeName[], i // Compare fastest times... will never be collapse all so ignore it // seconds_min = tiled MDRange - // seconds_min_c = collapse<2>-like MDRange (tiledim = span for fast dim) - only for non-Cuda, else tile too long - // seconds_2 = collapse<2>-style RangePolicy - // seconds_3 = collapse<3>-style RangePolicy + // seconds_min_c = collapse<2>-like MDRange (tiledim = span for fast dim) - + // only for non-Cuda, else tile too long seconds_2 = collapse<2>-style + // RangePolicy seconds_3 = collapse<3>-style RangePolicy #if !defined(KOKKOS_ENABLE_CUDA) - if ( seconds_min < seconds_min_c ) { - if ( seconds_min < seconds_2 ) { - std::cout << "--------------------------------------------------------------\n" - << " Fastest run: MDRange tiled\n" - << " Time: " << seconds_min - << " Difference: " << seconds_2 - seconds_min - << " Other times: \n" - << " MDrange collapse-like (tiledim = span on fast dim) type: " << seconds_min_c << "\n" - << " Collapse2 Range Policy: " << seconds_2 << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; - } - else if ( seconds_min > seconds_2 ) { - std::cout << " Fastest run: Collapse2 RangePolicy\n" - << " Time: " << seconds_2 - << " Difference: " << seconds_min - seconds_2 - << " Other times: \n" - << " MDrange Tiled: " << seconds_min << "\n" - << " MDrange collapse-like (tiledim = span on fast dim) type: " << seconds_min_c << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; - } - } - else if ( seconds_min > seconds_min_c ) { - if ( seconds_min_c < seconds_2 ) { - std::cout << "--------------------------------------------------------------\n" - << " Fastest run: MDRange collapse-like (tiledim = span on fast dim) type\n" - << " Time: " << seconds_min_c - << " Difference: " << seconds_2 - seconds_min_c - << " Other times: \n" - << " MDrange Tiled: " << seconds_min << "\n" - << " Collapse2 Range Policy: " << seconds_2 << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; + if (seconds_min < seconds_min_c) { + if (seconds_min < seconds_2) { + std::cout + << "--------------------------------------------------------------" + "\n" + << " Fastest run: MDRange tiled\n" + << " Time: " << seconds_min + << " Difference: " << seconds_2 - seconds_min << " Other times: \n" + << " MDrange collapse-like (tiledim = span on fast dim) type: " + << seconds_min_c << "\n" + << " Collapse2 Range Policy: " << seconds_2 << "\n" + << "\n-------------------------------------------------------------" + "-" + << "\n-------------------------------------------------------------" + "-" + //<< "\n\n" + << std::endl; + } else if (seconds_min > seconds_2) { + std::cout + << " Fastest run: Collapse2 RangePolicy\n" + << " Time: " << seconds_2 + << " Difference: " << seconds_min - seconds_2 << " Other times: \n" + << " MDrange Tiled: " << seconds_min << "\n" + << " MDrange collapse-like (tiledim = span on fast dim) type: " + << seconds_min_c << "\n" + << "\n-------------------------------------------------------------" + "-" + << "\n-------------------------------------------------------------" + "-" + //<< "\n\n" + << std::endl; } - else if ( seconds_min_c > seconds_2 ) { - std::cout << " Fastest run: Collapse2 RangePolicy\n" - << " Time: " << seconds_2 - << " Difference: " << seconds_min_c - seconds_2 - << " Other times: \n" - << " MDrange Tiled: " << seconds_min << "\n" - << " MDrange collapse-like (tiledim = span on fast dim) type: " << seconds_min_c << "\n" - << "\n--------------------------------------------------------------" - << "\n--------------------------------------------------------------" - //<< "\n\n" - << std::endl; + } else if (seconds_min > seconds_min_c) { + if (seconds_min_c < seconds_2) { + std::cout << "---------------------------------------------------------" + "-----\n" + << " Fastest run: MDRange collapse-like (tiledim = span on " + "fast dim) type\n" + << " Time: " << seconds_min_c + << " Difference: " << seconds_2 - seconds_min_c + << " Other times: \n" + << " MDrange Tiled: " << seconds_min << "\n" + << " Collapse2 Range Policy: " << seconds_2 << "\n" + << "\n-------------------------------------------------------" + "-------" + << "\n-------------------------------------------------------" + "-------" + //<< "\n\n" + << std::endl; + } else if (seconds_min_c > seconds_2) { + std::cout + << " Fastest run: Collapse2 RangePolicy\n" + << " Time: " << seconds_2 + << " Difference: " << seconds_min_c - seconds_2 + << " Other times: \n" + << " MDrange Tiled: " << seconds_min << "\n" + << " MDrange collapse-like (tiledim = span on fast dim) type: " + << seconds_min_c << "\n" + << "\n-------------------------------------------------------------" + "-" + << "\n-------------------------------------------------------------" + "-" + //<< "\n\n" + << std::endl; } - } // end else if + } // end else if #else - if ( seconds_min < seconds_2 ) { - std::cout << "--------------------------------------------------------------\n" + if (seconds_min < seconds_2) { + std::cout + << "--------------------------------------------------------------\n" << " Fastest run: MDRange tiled\n" << " Time: " << seconds_min - << " Difference: " << seconds_2 - seconds_min - << " Other times: \n" + << " Difference: " << seconds_2 - seconds_min << " Other times: \n" << " Collapse2 Range Policy: " << seconds_2 << "\n" << "\n--------------------------------------------------------------" << "\n--------------------------------------------------------------" //<< "\n\n" << std::endl; - } - else if ( seconds_min > seconds_2 ) { - std::cout << " Fastest run: Collapse2 RangePolicy\n" + } else if (seconds_min > seconds_2) { + std::cout + << " Fastest run: Collapse2 RangePolicy\n" << " Time: " << seconds_2 - << " Difference: " << seconds_min - seconds_2 - << " Other times: \n" + << " Difference: " << seconds_min - seconds_2 << " Other times: \n" << " MDrange Tiled: " << seconds_min << "\n" << "\n--------------------------------------------------------------" << "\n--------------------------------------------------------------" //<< "\n\n" << std::endl; - } + } #endif - } //end for + } // end for #undef MDRANGE_PERFORMANCE_OUTPUT_VERBOSE - -} - - } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp b/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp index d812b16d85..5e85163acf 100644 --- a/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp +++ b/lib/kokkos/core/perf_test/PerfTestGramSchmidt.cpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -55,131 +56,105 @@ namespace Test { // Reduction : result = dot( Q(:,j) , Q(:,j) ); // PostProcess : R(j,j) = result ; inv = 1 / result ; -template< class VectorView , class ValueView > -struct InvNorm2 : public Kokkos::DotSingle< VectorView > { +template +struct InvNorm2 : public Kokkos::DotSingle { + typedef typename Kokkos::DotSingle::value_type value_type; - typedef typename Kokkos::DotSingle< VectorView >::value_type value_type ; + ValueView Rjj; + ValueView inv; - ValueView Rjj ; - ValueView inv ; - - InvNorm2( const VectorView & argX , - const ValueView & argR , - const ValueView & argInv ) - : Kokkos::DotSingle< VectorView >( argX ) - , Rjj( argR ) - , inv( argInv ) - {} + InvNorm2(const VectorView& argX, const ValueView& argR, + const ValueView& argInv) + : Kokkos::DotSingle(argX), Rjj(argR), inv(argInv) {} KOKKOS_INLINE_FUNCTION - void final( value_type & result ) const - { - result = std::sqrt( result ); - Rjj() = result ; - inv() = ( 0 < result ) ? 1.0 / result : 0 ; + void final(value_type& result) const { + result = std::sqrt(result); + Rjj() = result; + inv() = (0 < result) ? 1.0 / result : 0; } }; -template< class VectorView , class ValueView > -inline -void invnorm2( const VectorView & x , - const ValueView & r , - const ValueView & r_inv ) -{ - Kokkos::parallel_reduce( x.extent(0) , InvNorm2< VectorView , ValueView >( x , r , r_inv ) ); +template +inline void invnorm2(const VectorView& x, const ValueView& r, + const ValueView& r_inv) { + Kokkos::parallel_reduce(x.extent(0), + InvNorm2(x, r, r_inv)); } // PostProcess : tmp = - ( R(j,k) = result ); -template< class VectorView , class ValueView > -struct DotM : public Kokkos::Dot< VectorView > { - - typedef typename Kokkos::Dot< VectorView >::value_type value_type ; +template +struct DotM : public Kokkos::Dot { + typedef typename Kokkos::Dot::value_type value_type; - ValueView Rjk ; - ValueView tmp ; + ValueView Rjk; + ValueView tmp; - DotM( const VectorView & argX , - const VectorView & argY , - const ValueView & argR , - const ValueView & argTmp ) - : Kokkos::Dot< VectorView >( argX , argY ) - , Rjk( argR ) - , tmp( argTmp ) - {} + DotM(const VectorView& argX, const VectorView& argY, const ValueView& argR, + const ValueView& argTmp) + : Kokkos::Dot(argX, argY), Rjk(argR), tmp(argTmp) {} KOKKOS_INLINE_FUNCTION - void final( value_type & result ) const - { - Rjk() = result ; - tmp() = - result ; + void final(value_type& result) const { + Rjk() = result; + tmp() = -result; } }; -template< class VectorView , class ValueView > -inline -void dot_neg( const VectorView & x , - const VectorView & y , - const ValueView & r , - const ValueView & r_neg ) -{ - Kokkos::parallel_reduce( x.extent(0) , DotM< VectorView , ValueView >( x , y , r , r_neg ) ); +template +inline void dot_neg(const VectorView& x, const VectorView& y, + const ValueView& r, const ValueView& r_neg) { + Kokkos::parallel_reduce(x.extent(0), + DotM(x, y, r, r_neg)); } +template +struct ModifiedGramSchmidt { + typedef DeviceType execution_space; + typedef typename execution_space::size_type size_type; -template< typename Scalar , class DeviceType > -struct ModifiedGramSchmidt -{ - typedef DeviceType execution_space ; - typedef typename execution_space::size_type size_type ; - - typedef Kokkos::View< Scalar** , - Kokkos::LayoutLeft , - execution_space > multivector_type ; - - typedef Kokkos::View< Scalar* , - Kokkos::LayoutLeft , - execution_space > vector_type ; + typedef Kokkos::View + multivector_type; - typedef Kokkos::View< Scalar , - Kokkos::LayoutLeft , - execution_space > value_view ; + typedef Kokkos::View + vector_type; + typedef Kokkos::View value_view; - multivector_type Q ; - multivector_type R ; + multivector_type Q; + multivector_type R; - static double factorization( const multivector_type Q_ , - const multivector_type R_ ) - { - const size_type count = Q_.extent(1); + static double factorization(const multivector_type Q_, + const multivector_type R_) { + const size_type count = Q_.extent(1); value_view tmp("tmp"); value_view one("one"); - Kokkos::deep_copy( one , (Scalar) 1 ); + Kokkos::deep_copy(one, (Scalar)1); - Kokkos::Timer timer ; + Kokkos::Timer timer; - for ( size_type j = 0 ; j < count ; ++j ) { + for (size_type j = 0; j < count; ++j) { // Reduction : tmp = dot( Q(:,j) , Q(:,j) ); // PostProcess : tmp = std::sqrt( tmp ); R(j,j) = tmp ; tmp = 1 / tmp ; - const vector_type Qj = Kokkos::subview( Q_ , Kokkos::ALL() , j ); - const value_view Rjj = Kokkos::subview( R_ , j , j ); + const vector_type Qj = Kokkos::subview(Q_, Kokkos::ALL(), j); + const value_view Rjj = Kokkos::subview(R_, j, j); - invnorm2( Qj , Rjj , tmp ); + invnorm2(Qj, Rjj, tmp); // Q(:,j) *= ( 1 / R(j,j) ); => Q(:,j) *= tmp ; - Kokkos::scale( tmp , Qj ); + Kokkos::scale(tmp, Qj); - for ( size_t k = j + 1 ; k < count ; ++k ) { - const vector_type Qk = Kokkos::subview( Q_ , Kokkos::ALL() , k ); - const value_view Rjk = Kokkos::subview( R_ , j , k ); + for (size_t k = j + 1; k < count; ++k) { + const vector_type Qk = Kokkos::subview(Q_, Kokkos::ALL(), k); + const value_view Rjk = Kokkos::subview(R_, j, k); // Reduction : R(j,k) = dot( Q(:,j) , Q(:,k) ); // PostProcess : tmp = - R(j,k); - dot_neg( Qj , Qk , Rjk , tmp ); + dot_neg(Qj, Qk, Rjk, tmp); // Q(:,k) -= R(j,k) * Q(:,j); => Q(:,k) += tmp * Q(:,j) - Kokkos::axpby( tmp , Qj , one , Qk ); + Kokkos::axpby(tmp, Qj, one, Qk); } } @@ -190,94 +165,87 @@ struct ModifiedGramSchmidt //-------------------------------------------------------------------------- - static double test( const size_t length , - const size_t count , - const size_t iter = 1 ) - { - multivector_type Q_( "Q" , length , count ); - multivector_type R_( "R" , count , count ); + static double test(const size_t length, const size_t count, + const size_t iter = 1) { + multivector_type Q_("Q", length, count); + multivector_type R_("R", count, count); - typename multivector_type::HostMirror A = - Kokkos::create_mirror( Q_ ); + typename multivector_type::HostMirror A = Kokkos::create_mirror(Q_); // Create and fill A on the host - for ( size_type j = 0 ; j < count ; ++j ) { - for ( size_type i = 0 ; i < length ; ++i ) { - A(i,j) = ( i + 1 ) * ( j + 1 ); + for (size_type j = 0; j < count; ++j) { + for (size_type i = 0; i < length; ++i) { + A(i, j) = (i + 1) * (j + 1); } } - double dt_min = 0 ; + double dt_min = 0; - for ( size_t i = 0 ; i < iter ; ++i ) { - - Kokkos::deep_copy( Q_ , A ); + for (size_t i = 0; i < iter; ++i) { + Kokkos::deep_copy(Q_, A); // A = Q * R - const double dt = factorization( Q_ , R_ ); + const double dt = factorization(Q_, R_); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; } - return dt_min ; + return dt_min; } }; -template< class DeviceType > -void run_test_gramschmidt( int exp_beg , int exp_end, int num_trials, const char deviceTypeName[] ) -{ - std::string label_gramschmidt ; - label_gramschmidt.append( "\"GramSchmidt< double , " ); - label_gramschmidt.append( deviceTypeName ); - label_gramschmidt.append( " >\"" ); - - for (int i = exp_beg ; i < exp_end ; ++i) { - double min_seconds = 0.0 ; - double max_seconds = 0.0 ; - double avg_seconds = 0.0 ; - - const int parallel_work_length = 1<::test(parallel_work_length, 32 ) ; - - if ( 0 == j ) { - min_seconds = seconds ; - max_seconds = seconds ; - } - else { - if ( seconds < min_seconds ) min_seconds = seconds ; - if ( seconds > max_seconds ) max_seconds = seconds ; +template +void run_test_gramschmidt(int exp_beg, int exp_end, int num_trials, + const char deviceTypeName[]) { + std::string label_gramschmidt; + label_gramschmidt.append("\"GramSchmidt< double , "); + label_gramschmidt.append(deviceTypeName); + label_gramschmidt.append(" >\""); + + for (int i = exp_beg; i < exp_end; ++i) { + double min_seconds = 0.0; + double max_seconds = 0.0; + double avg_seconds = 0.0; + + const int parallel_work_length = 1 << i; + + for (int j = 0; j < num_trials; ++j) { + const double seconds = ModifiedGramSchmidt::test( + parallel_work_length, 32); + + if (0 == j) { + min_seconds = seconds; + max_seconds = seconds; + } else { + if (seconds < min_seconds) min_seconds = seconds; + if (seconds > max_seconds) max_seconds = seconds; } - avg_seconds += seconds ; + avg_seconds += seconds; } - avg_seconds /= num_trials ; + avg_seconds /= num_trials; - std::cout << label_gramschmidt - << " , " << parallel_work_length - << " , " << min_seconds - << " , " << ( min_seconds / parallel_work_length ) - << std::endl ; + std::cout << label_gramschmidt << " , " << parallel_work_length << " , " + << min_seconds << " , " << (min_seconds / parallel_work_length) + << std::endl; } } -TEST_F( default_exec, gramschmidt ) { - int exp_beg = 10; - int exp_end = 20; +TEST(default_exec, gramschmidt) { + int exp_beg = 10; + int exp_end = 20; int num_trials = 5; - if(command_line_num_args()>1) - exp_beg = atoi(command_line_arg(1)); - if(command_line_num_args()>2) - exp_end = atoi(command_line_arg(2)); - if(command_line_num_args()>3) - num_trials = atoi(command_line_arg(3)); - - EXPECT_NO_THROW(run_test_gramschmidt< Kokkos::DefaultExecutionSpace>( exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name() )); -} + if (command_line_num_args() > 1) exp_beg = atoi(command_line_arg(1)); + if (command_line_num_args() > 2) exp_end = atoi(command_line_arg(2)); + if (command_line_num_args() > 3) num_trials = atoi(command_line_arg(3)); + EXPECT_NO_THROW(run_test_gramschmidt( + exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name())); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp b/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp index 03285a375c..d879282867 100644 --- a/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp +++ b/lib/kokkos/core/perf_test/PerfTestHexGrad.cpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -47,279 +48,253 @@ namespace Test { -template< class DeviceType , - typename CoordScalarType = double , - typename GradScalarType = float > -struct HexGrad -{ - typedef DeviceType execution_space ; - typedef typename execution_space::size_type size_type ; +template +struct HexGrad { + typedef DeviceType execution_space; + typedef typename execution_space::size_type size_type; - typedef HexGrad self_type; + typedef HexGrad self_type; // 3D array : ( ParallelWork , Space , Node ) - enum { NSpace = 3 , NNode = 8 }; + enum { NSpace = 3, NNode = 8 }; - typedef Kokkos::View< CoordScalarType*[NSpace][NNode] , execution_space > - elem_coord_type ; + typedef Kokkos::View + elem_coord_type; - typedef Kokkos::View< GradScalarType*[NSpace][NNode] , execution_space > - elem_grad_type ; + typedef Kokkos::View + elem_grad_type; - elem_coord_type coords ; - elem_grad_type grad_op ; + elem_coord_type coords; + elem_grad_type grad_op; - enum { FLOPS = 318 }; // = 3 * ( 18 + 8 * 11 ) }; - enum { READS = 18 }; + enum { FLOPS = 318 }; // = 3 * ( 18 + 8 * 11 ) }; + enum { READS = 18 }; enum { WRITES = 18 }; - HexGrad( const elem_coord_type & arg_coords , - const elem_grad_type & arg_grad_op ) - : coords( arg_coords ) - , grad_op( arg_grad_op ) - {} - - KOKKOS_INLINE_FUNCTION static - void grad( const CoordScalarType x[] , - const CoordScalarType z[] , - GradScalarType grad_y[] ) - { - const GradScalarType R42=(x[3] - x[1]); - const GradScalarType R52=(x[4] - x[1]); - const GradScalarType R54=(x[4] - x[3]); - - const GradScalarType R63=(x[5] - x[2]); - const GradScalarType R83=(x[7] - x[2]); - const GradScalarType R86=(x[7] - x[5]); - - const GradScalarType R31=(x[2] - x[0]); - const GradScalarType R61=(x[5] - x[0]); - const GradScalarType R74=(x[6] - x[3]); - - const GradScalarType R72=(x[6] - x[1]); - const GradScalarType R75=(x[6] - x[4]); - const GradScalarType R81=(x[7] - x[0]); - - const GradScalarType t1=(R63 + R54); - const GradScalarType t2=(R61 + R74); - const GradScalarType t3=(R72 + R81); - - const GradScalarType t4 =(R86 + R42); - const GradScalarType t5 =(R83 + R52); - const GradScalarType t6 =(R75 + R31); + HexGrad(const elem_coord_type& arg_coords, const elem_grad_type& arg_grad_op) + : coords(arg_coords), grad_op(arg_grad_op) {} + + KOKKOS_INLINE_FUNCTION static void grad(const CoordScalarType x[], + const CoordScalarType z[], + GradScalarType grad_y[]) { + const GradScalarType R42 = (x[3] - x[1]); + const GradScalarType R52 = (x[4] - x[1]); + const GradScalarType R54 = (x[4] - x[3]); + + const GradScalarType R63 = (x[5] - x[2]); + const GradScalarType R83 = (x[7] - x[2]); + const GradScalarType R86 = (x[7] - x[5]); + + const GradScalarType R31 = (x[2] - x[0]); + const GradScalarType R61 = (x[5] - x[0]); + const GradScalarType R74 = (x[6] - x[3]); + + const GradScalarType R72 = (x[6] - x[1]); + const GradScalarType R75 = (x[6] - x[4]); + const GradScalarType R81 = (x[7] - x[0]); + + const GradScalarType t1 = (R63 + R54); + const GradScalarType t2 = (R61 + R74); + const GradScalarType t3 = (R72 + R81); + + const GradScalarType t4 = (R86 + R42); + const GradScalarType t5 = (R83 + R52); + const GradScalarType t6 = (R75 + R31); // Calculate Y gradient from X and Z data - grad_y[0] = (z[1] * t1) - (z[2] * R42) - (z[3] * t5) + (z[4] * t4) + (z[5] * R52) - (z[7] * R54); - grad_y[1] = (z[2] * t2) + (z[3] * R31) - (z[0] * t1) - (z[5] * t6) + (z[6] * R63) - (z[4] * R61); - grad_y[2] = (z[3] * t3) + (z[0] * R42) - (z[1] * t2) - (z[6] * t4) + (z[7] * R74) - (z[5] * R72); - grad_y[3] = (z[0] * t5) - (z[1] * R31) - (z[2] * t3) + (z[7] * t6) + (z[4] * R81) - (z[6] * R83); - grad_y[4] = (z[5] * t3) + (z[6] * R86) - (z[7] * t2) - (z[0] * t4) - (z[3] * R81) + (z[1] * R61); - grad_y[5] = (z[6] * t5) - (z[4] * t3) - (z[7] * R75) + (z[1] * t6) - (z[0] * R52) + (z[2] * R72); - grad_y[6] = (z[7] * t1) - (z[5] * t5) - (z[4] * R86) + (z[2] * t4) - (z[1] * R63) + (z[3] * R83); - grad_y[7] = (z[4] * t2) - (z[6] * t1) + (z[5] * R75) - (z[3] * t6) - (z[2] * R74) + (z[0] * R54); + grad_y[0] = (z[1] * t1) - (z[2] * R42) - (z[3] * t5) + (z[4] * t4) + + (z[5] * R52) - (z[7] * R54); + grad_y[1] = (z[2] * t2) + (z[3] * R31) - (z[0] * t1) - (z[5] * t6) + + (z[6] * R63) - (z[4] * R61); + grad_y[2] = (z[3] * t3) + (z[0] * R42) - (z[1] * t2) - (z[6] * t4) + + (z[7] * R74) - (z[5] * R72); + grad_y[3] = (z[0] * t5) - (z[1] * R31) - (z[2] * t3) + (z[7] * t6) + + (z[4] * R81) - (z[6] * R83); + grad_y[4] = (z[5] * t3) + (z[6] * R86) - (z[7] * t2) - (z[0] * t4) - + (z[3] * R81) + (z[1] * R61); + grad_y[5] = (z[6] * t5) - (z[4] * t3) - (z[7] * R75) + (z[1] * t6) - + (z[0] * R52) + (z[2] * R72); + grad_y[6] = (z[7] * t1) - (z[5] * t5) - (z[4] * R86) + (z[2] * t4) - + (z[1] * R63) + (z[3] * R83); + grad_y[7] = (z[4] * t2) - (z[6] * t1) + (z[5] * R75) - (z[3] * t6) - + (z[2] * R74) + (z[0] * R54); } KOKKOS_INLINE_FUNCTION - void operator()( size_type ielem ) const - { - GradScalarType g[NNode] ; - - const CoordScalarType x[NNode] = { - coords(ielem,0,0), - coords(ielem,0,1), - coords(ielem,0,2), - coords(ielem,0,3), - coords(ielem,0,4), - coords(ielem,0,5), - coords(ielem,0,6), - coords(ielem,0,7) - }; - - const CoordScalarType y[NNode] = { - coords(ielem,1,0), - coords(ielem,1,1), - coords(ielem,1,2), - coords(ielem,1,3), - coords(ielem,1,4), - coords(ielem,1,5), - coords(ielem,1,6), - coords(ielem,1,7) - }; - - const CoordScalarType z[NNode] = { - coords(ielem,2,0), - coords(ielem,2,1), - coords(ielem,2,2), - coords(ielem,2,3), - coords(ielem,2,4), - coords(ielem,2,5), - coords(ielem,2,6), - coords(ielem,2,7) - }; - - grad( z , y , g ); - - grad_op(ielem,0,0) = g[0]; - grad_op(ielem,0,1) = g[1]; - grad_op(ielem,0,2) = g[2]; - grad_op(ielem,0,3) = g[3]; - grad_op(ielem,0,4) = g[4]; - grad_op(ielem,0,5) = g[5]; - grad_op(ielem,0,6) = g[6]; - grad_op(ielem,0,7) = g[7]; - - grad( x , z , g ); - - grad_op(ielem,1,0) = g[0]; - grad_op(ielem,1,1) = g[1]; - grad_op(ielem,1,2) = g[2]; - grad_op(ielem,1,3) = g[3]; - grad_op(ielem,1,4) = g[4]; - grad_op(ielem,1,5) = g[5]; - grad_op(ielem,1,6) = g[6]; - grad_op(ielem,1,7) = g[7]; - - grad( y , x , g ); - - grad_op(ielem,2,0) = g[0]; - grad_op(ielem,2,1) = g[1]; - grad_op(ielem,2,2) = g[2]; - grad_op(ielem,2,3) = g[3]; - grad_op(ielem,2,4) = g[4]; - grad_op(ielem,2,5) = g[5]; - grad_op(ielem,2,6) = g[6]; - grad_op(ielem,2,7) = g[7]; + void operator()(size_type ielem) const { + GradScalarType g[NNode]; + + const CoordScalarType x[NNode] = {coords(ielem, 0, 0), coords(ielem, 0, 1), + coords(ielem, 0, 2), coords(ielem, 0, 3), + coords(ielem, 0, 4), coords(ielem, 0, 5), + coords(ielem, 0, 6), coords(ielem, 0, 7)}; + + const CoordScalarType y[NNode] = {coords(ielem, 1, 0), coords(ielem, 1, 1), + coords(ielem, 1, 2), coords(ielem, 1, 3), + coords(ielem, 1, 4), coords(ielem, 1, 5), + coords(ielem, 1, 6), coords(ielem, 1, 7)}; + + const CoordScalarType z[NNode] = {coords(ielem, 2, 0), coords(ielem, 2, 1), + coords(ielem, 2, 2), coords(ielem, 2, 3), + coords(ielem, 2, 4), coords(ielem, 2, 5), + coords(ielem, 2, 6), coords(ielem, 2, 7)}; + + grad(z, y, g); + + grad_op(ielem, 0, 0) = g[0]; + grad_op(ielem, 0, 1) = g[1]; + grad_op(ielem, 0, 2) = g[2]; + grad_op(ielem, 0, 3) = g[3]; + grad_op(ielem, 0, 4) = g[4]; + grad_op(ielem, 0, 5) = g[5]; + grad_op(ielem, 0, 6) = g[6]; + grad_op(ielem, 0, 7) = g[7]; + + grad(x, z, g); + + grad_op(ielem, 1, 0) = g[0]; + grad_op(ielem, 1, 1) = g[1]; + grad_op(ielem, 1, 2) = g[2]; + grad_op(ielem, 1, 3) = g[3]; + grad_op(ielem, 1, 4) = g[4]; + grad_op(ielem, 1, 5) = g[5]; + grad_op(ielem, 1, 6) = g[6]; + grad_op(ielem, 1, 7) = g[7]; + + grad(y, x, g); + + grad_op(ielem, 2, 0) = g[0]; + grad_op(ielem, 2, 1) = g[1]; + grad_op(ielem, 2, 2) = g[2]; + grad_op(ielem, 2, 3) = g[3]; + grad_op(ielem, 2, 4) = g[4]; + grad_op(ielem, 2, 5) = g[5]; + grad_op(ielem, 2, 6) = g[6]; + grad_op(ielem, 2, 7) = g[7]; } //-------------------------------------------------------------------------- struct Init { - typedef typename self_type::execution_space execution_space ; + typedef typename self_type::execution_space execution_space; - elem_coord_type coords ; + elem_coord_type coords; - Init( const elem_coord_type & arg_coords ) - : coords( arg_coords ) {} + Init(const elem_coord_type& arg_coords) : coords(arg_coords) {} KOKKOS_INLINE_FUNCTION - void operator()( size_type ielem ) const - { - coords(ielem,0,0) = 0.; - coords(ielem,1,0) = 0.; - coords(ielem,2,0) = 0.; - - coords(ielem,0,1) = 1.; - coords(ielem,1,1) = 0.; - coords(ielem,2,1) = 0.; - - coords(ielem,0,2) = 1.; - coords(ielem,1,2) = 1.; - coords(ielem,2,2) = 0.; - - coords(ielem,0,3) = 0.; - coords(ielem,1,3) = 1.; - coords(ielem,2,3) = 0.; - - - coords(ielem,0,4) = 0.; - coords(ielem,1,4) = 0.; - coords(ielem,2,4) = 1.; - - coords(ielem,0,5) = 1.; - coords(ielem,1,5) = 0.; - coords(ielem,2,5) = 1.; - - coords(ielem,0,6) = 1.; - coords(ielem,1,6) = 1.; - coords(ielem,2,6) = 1.; - - coords(ielem,0,7) = 0.; - coords(ielem,1,7) = 1.; - coords(ielem,2,7) = 1.; + void operator()(size_type ielem) const { + coords(ielem, 0, 0) = 0.; + coords(ielem, 1, 0) = 0.; + coords(ielem, 2, 0) = 0.; + + coords(ielem, 0, 1) = 1.; + coords(ielem, 1, 1) = 0.; + coords(ielem, 2, 1) = 0.; + + coords(ielem, 0, 2) = 1.; + coords(ielem, 1, 2) = 1.; + coords(ielem, 2, 2) = 0.; + + coords(ielem, 0, 3) = 0.; + coords(ielem, 1, 3) = 1.; + coords(ielem, 2, 3) = 0.; + + coords(ielem, 0, 4) = 0.; + coords(ielem, 1, 4) = 0.; + coords(ielem, 2, 4) = 1.; + + coords(ielem, 0, 5) = 1.; + coords(ielem, 1, 5) = 0.; + coords(ielem, 2, 5) = 1.; + + coords(ielem, 0, 6) = 1.; + coords(ielem, 1, 6) = 1.; + coords(ielem, 2, 6) = 1.; + + coords(ielem, 0, 7) = 0.; + coords(ielem, 1, 7) = 1.; + coords(ielem, 2, 7) = 1.; } }; //-------------------------------------------------------------------------- - static double test( const int count , const int iter = 1 ) - { - elem_coord_type coord( "coord" , count ); - elem_grad_type grad ( "grad" , count ); + static double test(const int count, const int iter = 1) { + elem_coord_type coord("coord", count); + elem_grad_type grad("grad", count); // Execute the parallel kernels on the arrays: - double dt_min = 0 ; + double dt_min = 0; - Kokkos::parallel_for( count , Init( coord ) ); + Kokkos::parallel_for(count, Init(coord)); execution_space().fence(); - for ( int i = 0 ; i < iter ; ++i ) { - Kokkos::Timer timer ; - Kokkos::parallel_for( count , HexGrad( coord , grad ) ); + for (int i = 0; i < iter; ++i) { + Kokkos::Timer timer; + Kokkos::parallel_for(count, HexGrad(coord, grad)); execution_space().fence(); const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; } - return dt_min ; + return dt_min; } }; -template< class DeviceType > -void run_test_hexgrad( int exp_beg , int exp_end, int num_trials, const char deviceTypeName[] ) -{ - std::string label_hexgrad ; - label_hexgrad.append( "\"HexGrad< double , " ); - label_hexgrad.append( deviceTypeName ); - label_hexgrad.append( " >\"" ); - - for (int i = exp_beg ; i < exp_end ; ++i) { - double min_seconds = 0.0 ; - double max_seconds = 0.0 ; - double avg_seconds = 0.0 ; - - const int parallel_work_length = 1<::test(parallel_work_length) ; - - if ( 0 == j ) { - min_seconds = seconds ; - max_seconds = seconds ; +template +void run_test_hexgrad(int exp_beg, int exp_end, int num_trials, + const char deviceTypeName[]) { + std::string label_hexgrad; + label_hexgrad.append("\"HexGrad< double , "); + label_hexgrad.append(deviceTypeName); + label_hexgrad.append(" >\""); + + for (int i = exp_beg; i < exp_end; ++i) { + double min_seconds = 0.0; + double max_seconds = 0.0; + double avg_seconds = 0.0; + + const int parallel_work_length = 1 << i; + + for (int j = 0; j < num_trials; ++j) { + const double seconds = HexGrad::test(parallel_work_length); + + if (0 == j) { + min_seconds = seconds; + max_seconds = seconds; + } else { + if (seconds < min_seconds) min_seconds = seconds; + if (seconds > max_seconds) max_seconds = seconds; } - else { - if ( seconds < min_seconds ) min_seconds = seconds ; - if ( seconds > max_seconds ) max_seconds = seconds ; - } - avg_seconds += seconds ; + avg_seconds += seconds; } - avg_seconds /= num_trials ; + avg_seconds /= num_trials; - std::cout << label_hexgrad - << " , " << parallel_work_length - << " , " << min_seconds - << " , " << ( min_seconds / parallel_work_length ) - << std::endl ; + std::cout << label_hexgrad << " , " << parallel_work_length << " , " + << min_seconds << " , " << (min_seconds / parallel_work_length) + << std::endl; } } -TEST_F( default_exec, hexgrad ) { - int exp_beg = 10; - int exp_end = 20; +TEST(default_exec, hexgrad) { + int exp_beg = 10; + int exp_end = 20; int num_trials = 5; - if(command_line_num_args()>1) - exp_beg = atoi(command_line_arg(1)); - if(command_line_num_args()>2) - exp_end = atoi(command_line_arg(2)); - if(command_line_num_args()>3) - num_trials = atoi(command_line_arg(3)); - - EXPECT_NO_THROW(run_test_hexgrad< Kokkos::DefaultExecutionSpace >( exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name() )); -} + if (command_line_num_args() > 1) exp_beg = atoi(command_line_arg(1)); + if (command_line_num_args() > 2) exp_end = atoi(command_line_arg(2)); + if (command_line_num_args() > 3) num_trials = atoi(command_line_arg(3)); + EXPECT_NO_THROW(run_test_hexgrad( + exp_beg, exp_end, num_trials, Kokkos::DefaultExecutionSpace::name())); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTestMDRange.hpp b/lib/kokkos/core/perf_test/PerfTestMDRange.hpp index f433451f78..3afff96ff3 100644 --- a/lib/kokkos/core/perf_test/PerfTestMDRange.hpp +++ b/lib/kokkos/core/perf_test/PerfTestMDRange.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,24 +37,21 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ namespace Test { -template< class DeviceType - , typename ScalarType = double - , typename TestLayout = Kokkos::LayoutRight - > -struct MultiDimRangePerf3D -{ +template +struct MultiDimRangePerf3D { typedef DeviceType execution_space; - typedef typename execution_space::size_type size_type; + typedef typename execution_space::size_type size_type; using iterate_type = Kokkos::Iterate; - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; typedef typename view_type::HostMirror host_view_type; view_type A; @@ -62,39 +60,36 @@ struct MultiDimRangePerf3D const long jrange; const long krange; - MultiDimRangePerf3D(const view_type & A_, const view_type & B_, const long &irange_, const long &jrange_, const long &krange_) - : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) - {} + MultiDimRangePerf3D(const view_type &A_, const view_type &B_, + const long &irange_, const long &jrange_, + const long &krange_) + : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long i, const long j, const long k) const - { - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + void operator()(const long i, const long j, const long k) const { + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + B(i, j + 2, k) + + B(i, j + 1, k) + B(i, j, k + 2) + B(i, j, k + 1) + + B(i, j, k)); } - struct InitZeroTag {}; -// struct InitViewTag {}; - - struct Init - { + // struct InitViewTag {}; - Init(const view_type & input_, const long &irange_, const long &jrange_, const long &krange_) - : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} + struct Init { + Init(const view_type &input_, const long &irange_, const long &jrange_, + const long &krange_) + : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long i, const long j, const long k) const - { - input(i,j,k) = 1.0; + void operator()(const long i, const long j, const long k) const { + input(i, j, k) = 1.0; } KOKKOS_INLINE_FUNCTION - void operator()(const InitZeroTag&, const long i, const long j, const long k) const - { - input(i,j,k) = 0; + void operator()(const InitZeroTag &, const long i, const long j, + const long k) const { + input(i, j, k) = 0; } view_type input; @@ -103,166 +98,221 @@ struct MultiDimRangePerf3D const long krange; }; - - static double test_multi_index(const unsigned int icount, const unsigned int jcount, const unsigned int kcount, const unsigned int Ti = 1, const unsigned int Tj = 1, const unsigned int Tk = 1, const long iter = 1) - { - //This test performs multidim range over all dims + static double test_multi_index(const unsigned int icount, + const unsigned int jcount, + const unsigned int kcount, + const unsigned int Ti = 1, + const unsigned int Tj = 1, + const unsigned int Tk = 1, + const long iter = 1) { + // This test performs multidim range over all dims view_type Atest("Atest", icount, jcount, kcount); - view_type Btest("Btest", icount+2, jcount+2, kcount+2); - typedef MultiDimRangePerf3D FunctorType; + view_type Btest("Btest", icount + 2, jcount + 2, kcount + 2); + typedef MultiDimRangePerf3D + FunctorType; double dt_min = 0; // LayoutRight - if ( std::is_same::value ) { - Kokkos::MDRangePolicy, execution_space > policy_initA({{0,0,0}},{{icount,jcount,kcount}},{{Ti,Tj,Tk}}); - Kokkos::MDRangePolicy, execution_space > policy_initB({{0,0,0}},{{icount+2,jcount+2,kcount+2}},{{Ti,Tj,Tk}}); - - typedef typename Kokkos::MDRangePolicy, execution_space > MDRangeType; - using tile_type = typename MDRangeType::tile_type; + if (std::is_same::value) { + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + policy_initA({{0, 0, 0}}, {{icount, jcount, kcount}}, {{Ti, Tj, Tk}}); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + policy_initB({{0, 0, 0}}, {{icount + 2, jcount + 2, kcount + 2}}, + {{Ti, Tj, Tk}}); + + typedef typename Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + MDRangeType; + using tile_type = typename MDRangeType::tile_type; using point_type = typename MDRangeType::point_type; - Kokkos::MDRangePolicy, execution_space > policy(point_type{{0,0,0}},point_type{{icount,jcount,kcount}},tile_type{{Ti,Tj,Tk}} ); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Right, iterate_type::Right>, + execution_space> + policy(point_type{{0, 0, 0}}, point_type{{icount, jcount, kcount}}, + tile_type{{Ti, Tj, Tk}}); - Kokkos::parallel_for( policy_initA, Init(Atest, icount, jcount, kcount) ); + Kokkos::parallel_for(policy_initA, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest, icount+2, jcount+2, kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { - Kokkos::Timer timer; - Kokkos::parallel_for( policy, FunctorType(Atest, Btest, icount, jcount, kcount) ); - execution_space().fence(); - const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; - - //Correctness check - only the first run - if ( 0 == i ) - { - long numErrors = 0; - host_view_type Ahost("Ahost", icount, jcount, kcount); - Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); - Kokkos::deep_copy(Bhost, Btest); - - // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Correctness error at index: " << l << ","<(icount); ++l) { + for (long j = 0; j < static_cast(jcount); ++j) { + for (long k = 0; k < static_cast(kcount); ++k) { + ScalarType check = + 0.25 * + (ScalarType)(Bhost(l + 2, j, k) + Bhost(l + 1, j, k) + + Bhost(l, j + 2, k) + Bhost(l, j + 1, k) + + Bhost(l, j, k + 2) + Bhost(l, j, k + 1) + + Bhost(l, j, k)); + if (Ahost(l, j, k) - check != 0) { + ++numErrors; + std::cout << " Correctness error at index: " << l << "," << j + << "," << k << "\n" + << " multi Ahost = " << Ahost(l, j, k) + << " expected = " << check + << " multi Bhost(ijk) = " << Bhost(l, j, k) + << " multi Bhost(l+1jk) = " << Bhost(l + 1, j, k) + << " multi Bhost(l+2jk) = " << Bhost(l + 2, j, k) + << " multi Bhost(ij+1k) = " << Bhost(l, j + 1, k) + << " multi Bhost(ij+2k) = " << Bhost(l, j + 2, k) + << " multi Bhost(ijk+1) = " << Bhost(l, j, k + 1) + << " multi Bhost(ijk+2) = " << Bhost(l, j, k + 2) + << std::endl; + // exit(-1); + } + } + } } - } } } - if ( numErrors != 0 ) { std::cout << "LR multi: errors " << numErrors << " range product " << icount*jcount*kcount << " LL " << jcount*kcount << " LR " << icount*jcount << std::endl; } - //else { std::cout << " multi: No errors!" << std::endl; } - } - } //end for + if (numErrors != 0) { + std::cout << "LR multi: errors " << numErrors << " range product " + << icount * jcount * kcount << " LL " << jcount * kcount + << " LR " << icount * jcount << std::endl; + } + // else { std::cout << " multi: No errors!" << std::endl; } + } + } // end for - } + } // LayoutLeft else { - Kokkos::MDRangePolicy, execution_space > policy_initA({{0,0,0}},{{icount,jcount,kcount}},{{Ti,Tj,Tk}}); - Kokkos::MDRangePolicy, execution_space > policy_initB({{0,0,0}},{{icount+2,jcount+2,kcount+2}},{{Ti,Tj,Tk}}); - - //typedef typename Kokkos::MDRangePolicy, execution_space > MDRangeType; - //using tile_type = typename MDRangeType::tile_type; - //using point_type = typename MDRangeType::point_type; - //Kokkos::MDRangePolicy, execution_space > policy(point_type{{0,0,0}},point_type{{icount,jcount,kcount}},tile_type{{Ti,Tj,Tk}} ); - Kokkos::MDRangePolicy, execution_space > policy({{0,0,0}},{{icount,jcount,kcount}},{{Ti,Tj,Tk}} ); - - Kokkos::parallel_for( policy_initA, Init(Atest, icount, jcount, kcount) ); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Left, iterate_type::Left>, + execution_space> + policy_initA({{0, 0, 0}}, {{icount, jcount, kcount}}, {{Ti, Tj, Tk}}); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Left, iterate_type::Left>, + execution_space> + policy_initB({{0, 0, 0}}, {{icount + 2, jcount + 2, kcount + 2}}, + {{Ti, Tj, Tk}}); + + // typedef typename Kokkos::MDRangePolicy, execution_space > MDRangeType; + // using tile_type = typename MDRangeType::tile_type; + // using point_type = typename MDRangeType::point_type; + // Kokkos::MDRangePolicy, execution_space > + // policy(point_type{{0,0,0}},point_type{{icount,jcount,kcount}},tile_type{{Ti,Tj,Tk}} + // ); + Kokkos::MDRangePolicy< + Kokkos::Rank<3, iterate_type::Left, iterate_type::Left>, + execution_space> + policy({{0, 0, 0}}, {{icount, jcount, kcount}}, {{Ti, Tj, Tk}}); + + Kokkos::parallel_for(policy_initA, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest, icount+2, jcount+2, kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { - Kokkos::Timer timer; - Kokkos::parallel_for( policy, FunctorType(Atest, Btest, icount, jcount, kcount) ); - execution_space().fence(); - const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; - - //Correctness check - only the first run - if ( 0 == i ) - { - long numErrors = 0; - host_view_type Ahost("Ahost", icount, jcount, kcount); - Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); - Kokkos::deep_copy(Bhost, Btest); - - // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Correctness error at index: " << l << ","<(icount); ++l) { + for (long j = 0; j < static_cast(jcount); ++j) { + for (long k = 0; k < static_cast(kcount); ++k) { + ScalarType check = + 0.25 * + (ScalarType)(Bhost(l + 2, j, k) + Bhost(l + 1, j, k) + + Bhost(l, j + 2, k) + Bhost(l, j + 1, k) + + Bhost(l, j, k + 2) + Bhost(l, j, k + 1) + + Bhost(l, j, k)); + if (Ahost(l, j, k) - check != 0) { + ++numErrors; + std::cout << " Correctness error at index: " << l << "," << j + << "," << k << "\n" + << " multi Ahost = " << Ahost(l, j, k) + << " expected = " << check + << " multi Bhost(ijk) = " << Bhost(l, j, k) + << " multi Bhost(l+1jk) = " << Bhost(l + 1, j, k) + << " multi Bhost(l+2jk) = " << Bhost(l + 2, j, k) + << " multi Bhost(ij+1k) = " << Bhost(l, j + 1, k) + << " multi Bhost(ij+2k) = " << Bhost(l, j + 2, k) + << " multi Bhost(ijk+1) = " << Bhost(l, j, k + 1) + << " multi Bhost(ijk+2) = " << Bhost(l, j, k + 2) + << std::endl; + // exit(-1); + } + } + } } - } } } - if ( numErrors != 0 ) { std::cout << " LL multi run: errors " << numErrors << " range product " << icount*jcount*kcount << " LL " << jcount*kcount << " LR " << icount*jcount << std::endl; } - //else { std::cout << " multi: No errors!" << std::endl; } - - } - } //end for + if (numErrors != 0) { + std::cout << " LL multi run: errors " << numErrors + << " range product " << icount * jcount * kcount + << " LL " << jcount * kcount << " LR " + << icount * jcount << std::endl; + } + // else { std::cout << " multi: No errors!" << std::endl; } + } + } // end for } return dt_min; - } - + } }; - -template< class DeviceType - , typename ScalarType = double - , typename TestLayout = Kokkos::LayoutRight - > -struct RangePolicyCollapseTwo -{ - // RangePolicy for 3D range, but will collapse only 2 dims => like Rank<2> for multi-dim; unroll 2 dims in one-dim +template +struct RangePolicyCollapseTwo { + // RangePolicy for 3D range, but will collapse only 2 dims => like Rank<2> for + // multi-dim; unroll 2 dims in one-dim typedef DeviceType execution_space; - typedef typename execution_space::size_type size_type; + typedef typename execution_space::size_type size_type; typedef TestLayout layout; using iterate_type = Kokkos::Iterate; - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; typedef typename view_type::HostMirror host_view_type; view_type A; @@ -271,165 +321,170 @@ struct RangePolicyCollapseTwo const long jrange; const long krange; - RangePolicyCollapseTwo(view_type & A_, const view_type & B_, const long &irange_, const long &jrange_, const long &krange_) - : A(A_), B(B_) , irange(irange_), jrange(jrange_), krange(krange_) - {} + RangePolicyCollapseTwo(view_type &A_, const view_type &B_, + const long &irange_, const long &jrange_, + const long &krange_) + : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { -//id(i,j,k) = k + j*Nk + i*Nk*Nj = k + Nk*(j + i*Nj) = k + Nk*r -//r = j + i*Nj - long i = int(r / jrange); - long j = int( r - i*jrange); + void operator()(const long r) const { + if (std::is_same::value) { + // id(i,j,k) = k + j*Nk + i*Nk*Nj = k + Nk*(j + i*Nj) = k + Nk*r + // r = j + i*Nj + long i = int(r / jrange); + long j = int(r - i * jrange); for (int k = 0; k < krange; ++k) { - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + + B(i, j + 2, k) + B(i, j + 1, k) + + B(i, j, k + 2) + B(i, j, k + 1) + B(i, j, k)); } - } - else if ( std::is_same::value ) - { -//id(i,j,k) = i + j*Ni + k*Ni*Nj = i + Ni*(j + k*Nj) = i + Ni*r -//r = j + k*Nj - long k = int(r / jrange); - long j = int( r - k*jrange); + } else if (std::is_same::value) { + // id(i,j,k) = i + j*Ni + k*Ni*Nj = i + Ni*(j + k*Nj) = i + Ni*r + // r = j + k*Nj + long k = int(r / jrange); + long j = int(r - k * jrange); for (int i = 0; i < irange; ++i) { - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + + B(i, j + 2, k) + B(i, j + 1, k) + + B(i, j, k + 2) + B(i, j, k + 1) + B(i, j, k)); } } } - - struct Init - { + struct Init { view_type input; const long irange; const long jrange; const long krange; - Init(const view_type & input_, const long &irange_, const long &jrange_, const long &krange_) - : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} + Init(const view_type &input_, const long &irange_, const long &jrange_, + const long &krange_) + : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { - long i = int(r / jrange); - long j = int( r - i*jrange); + void operator()(const long r) const { + if (std::is_same::value) { + long i = int(r / jrange); + long j = int(r - i * jrange); for (int k = 0; k < krange; ++k) { - input(i,j,k) = 1; + input(i, j, k) = 1; } - } - else if ( std::is_same::value ) - { - long k = int(r / jrange); - long j = int( r - k*jrange); + } else if (std::is_same::value) { + long k = int(r / jrange); + long j = int(r - k * jrange); for (int i = 0; i < irange; ++i) { - input(i,j,k) = 1; + input(i, j, k) = 1; } } } }; - - static double test_index_collapse_two(const unsigned int icount, const unsigned int jcount, const unsigned int kcount, const long iter = 1) - { + static double test_index_collapse_two(const unsigned int icount, + const unsigned int jcount, + const unsigned int kcount, + const long iter = 1) { // This test refers to collapsing two dims while using the RangePolicy view_type Atest("Atest", icount, jcount, kcount); - view_type Btest("Btest", icount+2, jcount+2, kcount+2); - typedef RangePolicyCollapseTwo FunctorType; + view_type Btest("Btest", icount + 2, jcount + 2, kcount + 2); + typedef RangePolicyCollapseTwo + FunctorType; long collapse_index_rangeA = 0; long collapse_index_rangeB = 0; - if ( std::is_same::value ) { - collapse_index_rangeA = icount*jcount; - collapse_index_rangeB = (icount+2)*(jcount+2); -// std::cout << " LayoutRight " << std::endl; - } else if ( std::is_same::value ) { - collapse_index_rangeA = kcount*jcount; - collapse_index_rangeB = (kcount+2)*(jcount+2); -// std::cout << " LayoutLeft " << std::endl; + if (std::is_same::value) { + collapse_index_rangeA = icount * jcount; + collapse_index_rangeB = (icount + 2) * (jcount + 2); + // std::cout << " LayoutRight " << std::endl; + } else if (std::is_same::value) { + collapse_index_rangeA = kcount * jcount; + collapse_index_rangeB = (kcount + 2) * (jcount + 2); + // std::cout << " LayoutLeft " << std::endl; } else { - std::cout << " LayoutRight or LayoutLeft required - will pass 0 as range instead " << std::endl; + std::cout << " LayoutRight or LayoutLeft required - will pass 0 as " + "range instead " + << std::endl; exit(-1); } - Kokkos::RangePolicy policy(0, (collapse_index_rangeA) ); - Kokkos::RangePolicy policy_initB(0, (collapse_index_rangeB) ); + Kokkos::RangePolicy policy(0, (collapse_index_rangeA)); + Kokkos::RangePolicy policy_initB(0, + (collapse_index_rangeB)); double dt_min = 0; - Kokkos::parallel_for( policy, Init(Atest,icount,jcount,kcount) ); + Kokkos::parallel_for(policy, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest,icount+2,jcount+2,kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { + for (int i = 0; i < iter; ++i) { Kokkos::Timer timer; - Kokkos::parallel_for(policy, FunctorType(Atest, Btest, icount, jcount, kcount)); + Kokkos::parallel_for(policy, + FunctorType(Atest, Btest, icount, jcount, kcount)); execution_space().fence(); const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; - //Correctness check - first iteration only - if ( 0 == i ) - { + // Correctness check - first iteration only + if (0 == i) { long numErrors = 0; host_view_type Ahost("Ahost", icount, jcount, kcount); Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); + host_view_type Bhost("Bhost", icount + 2, jcount + 2, kcount + 2); Kokkos::deep_copy(Bhost, Btest); // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Correctness error at index: " << l << ","< -struct RangePolicyCollapseAll -{ +template +struct RangePolicyCollapseAll { // RangePolicy for 3D range, but will collapse all dims typedef DeviceType execution_space; - typedef typename execution_space::size_type size_type; + typedef typename execution_space::size_type size_type; typedef TestLayout layout; - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; typedef typename view_type::HostMirror host_view_type; view_type A; @@ -438,127 +493,134 @@ struct RangePolicyCollapseAll const long jrange; const long krange; - RangePolicyCollapseAll(view_type & A_, const view_type & B_, const long &irange_, const long &jrange_, const long &krange_) - : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) - {} + RangePolicyCollapseAll(view_type &A_, const view_type &B_, + const long &irange_, const long &jrange_, + const long &krange_) + : A(A_), B(B_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { - long i = int(r / (jrange*krange)); - long j = int(( r - i*jrange*krange)/krange); - long k = int(r - i*jrange*krange - j*krange); - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); - } - else if ( std::is_same::value ) - { - long k = int(r / (irange*jrange)); - long j = int(( r - k*irange*jrange)/irange); - long i = int(r - k*irange*jrange - j*irange); - A(i,j,k) = 0.25*(ScalarType)( B(i+2,j,k) + B(i+1,j,k) - + B(i,j+2,k) + B(i,j+1,k) - + B(i,j,k+2) + B(i,j,k+1) - + B(i,j,k) ); + void operator()(const long r) const { + if (std::is_same::value) { + long i = int(r / (jrange * krange)); + long j = int((r - i * jrange * krange) / krange); + long k = int(r - i * jrange * krange - j * krange); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + B(i, j + 2, k) + + B(i, j + 1, k) + B(i, j, k + 2) + B(i, j, k + 1) + + B(i, j, k)); + } else if (std::is_same::value) { + long k = int(r / (irange * jrange)); + long j = int((r - k * irange * jrange) / irange); + long i = int(r - k * irange * jrange - j * irange); + A(i, j, k) = + 0.25 * (ScalarType)(B(i + 2, j, k) + B(i + 1, j, k) + B(i, j + 2, k) + + B(i, j + 1, k) + B(i, j, k + 2) + B(i, j, k + 1) + + B(i, j, k)); } } - - struct Init - { + struct Init { view_type input; const long irange; const long jrange; const long krange; - Init(const view_type & input_, const long &irange_, const long &jrange_, const long &krange_) - : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} + Init(const view_type &input_, const long &irange_, const long &jrange_, + const long &krange_) + : input(input_), irange(irange_), jrange(jrange_), krange(krange_) {} KOKKOS_INLINE_FUNCTION - void operator()(const long r) const - { - if ( std::is_same::value ) - { - long i = int(r / (jrange*krange)); - long j = int(( r - i*jrange*krange)/krange); - long k = int(r - i*jrange*krange - j*krange); - input(i,j,k) = 1; - } - else if ( std::is_same::value ) - { - long k = int(r / (irange*jrange)); - long j = int(( r - k*irange*jrange)/irange); - long i = int(r - k*irange*jrange - j*irange); - input(i,j,k) = 1; + void operator()(const long r) const { + if (std::is_same::value) { + long i = int(r / (jrange * krange)); + long j = int((r - i * jrange * krange) / krange); + long k = int(r - i * jrange * krange - j * krange); + input(i, j, k) = 1; + } else if (std::is_same::value) { + long k = int(r / (irange * jrange)); + long j = int((r - k * irange * jrange) / irange); + long i = int(r - k * irange * jrange - j * irange); + input(i, j, k) = 1; } } }; - - static double test_collapse_all(const unsigned int icount, const unsigned int jcount, const unsigned int kcount, const long iter = 1) - { - //This test refers to collapsing all dims using the RangePolicy + static double test_collapse_all(const unsigned int icount, + const unsigned int jcount, + const unsigned int kcount, + const long iter = 1) { + // This test refers to collapsing all dims using the RangePolicy view_type Atest("Atest", icount, jcount, kcount); - view_type Btest("Btest", icount+2, jcount+2, kcount+2); - typedef RangePolicyCollapseAll FunctorType; + view_type Btest("Btest", icount + 2, jcount + 2, kcount + 2); + typedef RangePolicyCollapseAll + FunctorType; - const long flat_index_range = icount*jcount*kcount; - Kokkos::RangePolicy policy(0, flat_index_range ); - Kokkos::RangePolicy policy_initB(0, (icount+2)*(jcount+2)*(kcount+2) ); + const long flat_index_range = icount * jcount * kcount; + Kokkos::RangePolicy policy(0, flat_index_range); + Kokkos::RangePolicy policy_initB( + 0, (icount + 2) * (jcount + 2) * (kcount + 2)); double dt_min = 0; - Kokkos::parallel_for( policy, Init(Atest,icount,jcount,kcount) ); + Kokkos::parallel_for(policy, Init(Atest, icount, jcount, kcount)); execution_space().fence(); - Kokkos::parallel_for( policy_initB, Init(Btest,icount+2,jcount+2,kcount+2) ); + Kokkos::parallel_for(policy_initB, + Init(Btest, icount + 2, jcount + 2, kcount + 2)); execution_space().fence(); - for (int i = 0; i < iter; ++i) - { + for (int i = 0; i < iter; ++i) { Kokkos::Timer timer; - Kokkos::parallel_for(policy, FunctorType(Atest, Btest, icount, jcount, kcount)); + Kokkos::parallel_for(policy, + FunctorType(Atest, Btest, icount, jcount, kcount)); execution_space().fence(); const double dt = timer.seconds(); - if ( 0 == i ) dt_min = dt ; - else dt_min = dt < dt_min ? dt : dt_min ; + if (0 == i) + dt_min = dt; + else + dt_min = dt < dt_min ? dt : dt_min; - //Correctness check - first iteration only - if ( 0 == i ) - { + // Correctness check - first iteration only + if (0 == i) { long numErrors = 0; host_view_type Ahost("Ahost", icount, jcount, kcount); Kokkos::deep_copy(Ahost, Atest); - host_view_type Bhost("Bhost", icount+2, jcount+2, kcount+2); + host_view_type Bhost("Bhost", icount + 2, jcount + 2, kcount + 2); Kokkos::deep_copy(Bhost, Btest); // On KNL, this may vectorize - add print statement to prevent - // Also, compare against epsilon, as vectorization can change bitwise answer - for ( long l = 0; l < static_cast(icount); ++l ) { - for ( long j = 0; j < static_cast(jcount); ++j ) { - for ( long k = 0; k < static_cast(kcount); ++k ) { - ScalarType check = 0.25*(ScalarType)( Bhost(l+2,j,k) + Bhost(l+1,j,k) - + Bhost(l,j+2,k) + Bhost(l,j+1,k) - + Bhost(l,j,k+2) + Bhost(l,j,k+1) - + Bhost(l,j,k) ); - if ( Ahost(l,j,k) - check != 0 ) { - ++numErrors; - std::cout << " Callapse ALL Correctness error at index: " << l << ","<0) - n_args = n; + if (n > 0) n_args = n; return n_args; } const char* command_line_arg(int k, char** input_args = NULL) { static char** args; - if(input_args != NULL) - args = input_args; - if(command_line_num_args() > k) + if (input_args != NULL) args = input_args; + if (command_line_num_args() > k) return args[k]; else return NULL; } -} +} // namespace Test -int main(int argc, char *argv[]) { - ::testing::InitGoogleTest(&argc,argv); - Kokkos::initialize(argc,argv); +int main(int argc, char* argv[]) { + ::testing::InitGoogleTest(&argc, argv); + Kokkos::initialize(argc, argv); - (void) Test::command_line_num_args(argc); - (void) Test::command_line_arg(0,argv); + (void)Test::command_line_num_args(argc); + (void)Test::command_line_arg(0, argv); int result = RUN_ALL_TESTS(); diff --git a/lib/kokkos/core/perf_test/PerfTest_Category.hpp b/lib/kokkos/core/perf_test/PerfTest_Category.hpp index 18e309ab12..c2cff22502 100644 --- a/lib/kokkos/core/perf_test/PerfTest_Category.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_Category.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,16 +52,7 @@ namespace Test { extern int command_line_num_args(int n = 0); extern const char* command_line_arg(int k, char** input_args = NULL); -class default_exec : public ::testing::Test { -protected: - static void SetUpTestCase() { - } - - static void TearDownTestCase() { - } -}; - -} // namespace Test +} // namespace Test #define TEST_CATEGORY default_exec #define TEST_EXECSPACE Kokkos::DefaultExecutionSpace diff --git a/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp b/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp index 5c67084c6e..d06851ec9b 100644 --- a/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_CustomReduction.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,71 +49,90 @@ #ifdef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA namespace Test { -template +template void custom_reduction_test(int N, int R, int num_trials) { Kokkos::Random_XorShift64_Pool<> rand_pool(183291); - Kokkos::View a("A",N); - Kokkos::fill_random(a,rand_pool,1.0); + Kokkos::View a("A", N); + Kokkos::fill_random(a, rand_pool, 1.0); Scalar max; int team_size = 32; - if ( team_size > Kokkos::DefaultExecutionSpace::concurrency() ) + if (team_size > Kokkos::DefaultExecutionSpace::concurrency()) team_size = Kokkos::DefaultExecutionSpace::concurrency(); // Warm up - Kokkos::parallel_reduce(Kokkos::TeamPolicy<>(N/1024,team_size), KOKKOS_LAMBDA( const Kokkos::TeamPolicy<>::member_type& team, Scalar& lmax) { - Scalar team_max = Scalar(0); - for(int rr = 0; rrlmax) lmax = val; - if((k == 11) && (j==17) && (i==2)) lmax = 11.5; - },Kokkos::Max(t_max)); - if(t_max>thread_max) thread_max = t_max; - },Kokkos::Max(team_max)); - } - if(team_max>lmax) lmax = team_max; - },Kokkos::Max(max)); + Kokkos::parallel_reduce( + Kokkos::TeamPolicy<>(N / 1024, team_size), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type& team, + Scalar& lmax) { + Scalar team_max = Scalar(0); + for (int rr = 0; rr < R; rr++) { + int i = team.league_rank(); + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(team, 32), + [&](const int& j, Scalar& thread_max) { + Scalar t_max = Scalar(0); + Kokkos::parallel_reduce( + Kokkos::ThreadVectorRange(team, 32), + [&](const int& k, Scalar& max_) { + const Scalar val = a((i * 32 + j) * 32 + k); + if (val > lmax) lmax = val; + if ((k == 11) && (j == 17) && (i == 2)) lmax = 11.5; + }, + Kokkos::Max(t_max)); + if (t_max > thread_max) thread_max = t_max; + }, + Kokkos::Max(team_max)); + } + if (team_max > lmax) lmax = team_max; + }, + Kokkos::Max(max)); // Timing Kokkos::Timer timer; - for(int r = 0; r(N/1024,team_size), KOKKOS_LAMBDA( const Kokkos::TeamPolicy<>::member_type& team, Scalar& lmax) { - Scalar team_max = Scalar(0); - for(int rr = 0; rrlmax) lmax = val; - if((k == 11) && (j==17) && (i==2)) lmax = 11.5; - },Kokkos::Max(t_max)); - if(t_max>thread_max) thread_max = t_max; - },Kokkos::Max(team_max)); - } - if(team_max>lmax) lmax = team_max; - },Kokkos::Max(max)); + for (int r = 0; r < num_trials; r++) { + Kokkos::parallel_reduce( + Kokkos::TeamPolicy<>(N / 1024, team_size), + KOKKOS_LAMBDA(const Kokkos::TeamPolicy<>::member_type& team, + Scalar& lmax) { + Scalar team_max = Scalar(0); + for (int rr = 0; rr < R; rr++) { + int i = team.league_rank(); + Kokkos::parallel_reduce( + Kokkos::TeamThreadRange(team, 32), + [&](const int& j, Scalar& thread_max) { + Scalar t_max = Scalar(0); + Kokkos::parallel_reduce( + Kokkos::ThreadVectorRange(team, 32), + [&](const int& k, Scalar& max_) { + const Scalar val = a((i * 32 + j) * 32 + k); + if (val > lmax) lmax = val; + if ((k == 11) && (j == 17) && (i == 2)) lmax = 11.5; + }, + Kokkos::Max(t_max)); + if (t_max > thread_max) thread_max = t_max; + }, + Kokkos::Max(team_max)); + } + if (team_max > lmax) lmax = team_max; + }, + Kokkos::Max(max)); } double time = timer.seconds(); - printf("%e %e %e\n",time,1.0*N*R*num_trials*sizeof(Scalar)/time/1024/1024/1024,max); + printf("%e %e %e\n", time, + 1.0 * N * R * num_trials * sizeof(Scalar) / time / 1024 / 1024 / 1024, + max); } -TEST_F( default_exec, custom_reduction ) { - int N = 100000; - int R = 1000; +TEST(default_exec, custom_reduction) { + int N = 100000; + int R = 1000; int num_trials = 1; - if(command_line_num_args()>1) - N = atoi(command_line_arg(1)); - if(command_line_num_args()>2) - R = atoi(command_line_arg(2)); - if(command_line_num_args()>3) - num_trials = atoi(command_line_arg(3)); - custom_reduction_test(N,R,num_trials); -} + if (command_line_num_args() > 1) N = atoi(command_line_arg(1)); + if (command_line_num_args() > 2) R = atoi(command_line_arg(2)); + if (command_line_num_args() > 3) num_trials = atoi(command_line_arg(3)); + custom_reduction_test(N, R, num_trials); } +} // namespace Test #endif diff --git a/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp b/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp index 2fc889beed..c6d5b2b8d6 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ExecSpacePartitioning.cpp @@ -2,563 +2,631 @@ #include #include - namespace Test { namespace { - template - struct SpaceInstance { - static ExecSpace create() { - return ExecSpace(); - } - static void destroy(ExecSpace&) { - } - static bool overlap() { - return false; - } - }; - - #ifndef KOKKOS_ENABLE_DEBUG - #ifdef KOKKOS_ENABLE_CUDA - template<> - struct SpaceInstance { - static Kokkos::Cuda create() { - cudaStream_t stream; - cudaStreamCreate(&stream); - return Kokkos::Cuda(stream); - } - static void destroy(Kokkos::Cuda& space) { - cudaStream_t stream = space.cuda_stream(); - cudaStreamDestroy(stream); - } - static bool overlap() { - bool value = true; - auto local_rank_str = std::getenv("CUDA_LAUNCH_BLOCKING"); - if(local_rank_str) { - value = (std::atoi(local_rank_str)==0); - } - return value; +template +struct SpaceInstance { + static ExecSpace create() { return ExecSpace(); } + static void destroy(ExecSpace&) {} + static bool overlap() { return false; } +}; + +#ifndef KOKKOS_ENABLE_DEBUG +#ifdef KOKKOS_ENABLE_CUDA +template <> +struct SpaceInstance { + static Kokkos::Cuda create() { + cudaStream_t stream; + cudaStreamCreate(&stream); + return Kokkos::Cuda(stream); + } + static void destroy(Kokkos::Cuda& space) { + cudaStream_t stream = space.cuda_stream(); + cudaStreamDestroy(stream); + } + static bool overlap() { + bool value = true; + auto local_rank_str = std::getenv("CUDA_LAUNCH_BLOCKING"); + if (local_rank_str) { + value = (std::atoi(local_rank_str) == 0); } - }; - #endif - #endif -} + return value; + } +}; +#endif +#endif +} // namespace struct FunctorRange { - int M,R; - Kokkos::View a; - FunctorRange(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorRange(int M_, int R_, Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i) const { - for(int r=0;r a; - FunctorMDRange(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorMDRange(int M_, int R_, Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i, const int) const { - for(int j=0;j a; - FunctorTeam(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorTeam(int M_, int R_, + Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const Kokkos::TeamPolicy::member_type& team) const { + void operator()( + const Kokkos::TeamPolicy::member_type& team) const { int i = team.league_rank(); - for(int r=0;r a; - FunctorRangeReduce(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorRangeReduce(int M_, int R_, Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i, double& tmp) const { - for(int r=0;r a; - FunctorMDRangeReduce(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorMDRangeReduce(int M_, int R_, + Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const int i, const int, double& tmp) const { - for(int j=0;j a; - FunctorTeamReduce(int M_, int R_, Kokkos::View a_):M(M_),R(R_),a(a_){} + int M, R; + Kokkos::View a; + FunctorTeamReduce( + int M_, int R_, + Kokkos::View a_) + : M(M_), R(R_), a(a_) {} KOKKOS_INLINE_FUNCTION - void operator() (const Kokkos::TeamPolicy::member_type& team, double& tmp) const { + void operator()(const Kokkos::TeamPolicy::member_type& team, + double& tmp) const { int i = team.league_rank(); - for(int r=0;r::create(); - TEST_EXECSPACE space2 = SpaceInstance::create(); - - Kokkos::View a("A",N,M); - FunctorRange f(M,R,a); - FunctorRangeReduce fr(M,R,a); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", - Kokkos::RangePolicy(0,N), FunctorRange(M,R,a)); - - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel1", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space1,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel2", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space2,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - Kokkos::Timer timer; - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel3", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel4", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel5", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space1,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorRange(M,R,a)); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel6", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space2,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorRange(M,R,a)); - Kokkos::fence(); - double time_overlap = timer.seconds(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel7", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel8", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - double time_end = timer.seconds(); - - if(SpaceInstance::overlap()) { - ASSERT_TRUE( (time_end > 1.5*time_overlap) ); - } - printf("Time RangePolicy: NonOverlap: %lf Time Overlap: %lf\n",time_end,time_overlap); - - Kokkos::View result("result"); - Kokkos::View result1("result1"); - Kokkos::View result2("result2"); - Kokkos::View h_result("h_result"); - Kokkos::View h_result1("h_result1"); - Kokkos::View h_result2("h_result2"); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::fence(); - double time_fenced = timer.seconds(); - Kokkos::deep_copy(h_result,result); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - double time_not_fenced = timer.seconds(); - Kokkos::fence(); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_fenced>2.0*time_not_fenced); - } - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); + int M = 10000; + int R = 10; + + TEST_EXECSPACE space; + TEST_EXECSPACE space1 = SpaceInstance::create(); + TEST_EXECSPACE space2 = SpaceInstance::create(); + + Kokkos::View a("A", N, M); + FunctorRange f(M, R, a); + FunctorRangeReduce fr(M, R, a); + Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", + Kokkos::RangePolicy(0, N), + FunctorRange(M, R, a)); + + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel1", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space1, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel2", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space2, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + Kokkos::Timer timer; + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel3", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel4", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel5", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space1, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorRange(M, R, a)); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel6", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space2, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorRange(M, R, a)); + Kokkos::fence(); + double time_overlap = timer.seconds(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel7", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel8", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + double time_end = timer.seconds(); + + if (SpaceInstance::overlap()) { + ASSERT_TRUE((time_end > 1.5 * time_overlap)); + } + printf("Time RangePolicy: NonOverlap: %lf Time Overlap: %lf\n", time_end, + time_overlap); + + Kokkos::View result("result"); + Kokkos::View result1("result1"); + Kokkos::View result2("result2"); + Kokkos::View h_result("h_result"); + Kokkos::View h_result1("h_result1"); + Kokkos::View h_result2("h_result2"); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::fence(); + double time_fenced = timer.seconds(); + Kokkos::deep_copy(h_result, result); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + double time_not_fenced = timer.seconds(); + Kokkos::fence(); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_fenced > 2.0 * time_not_fenced); + } + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); Kokkos::fence(); double time_no_overlapped_reduce = timer.seconds(); - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space1,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result1); - Kokkos::parallel_reduce("default_exec::overlap_range_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::RangePolicy(space2,0,N), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result2); + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space1, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result1); + Kokkos::parallel_reduce( + "default_exec::overlap_range_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::RangePolicy(space2, 0, N), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result2); Kokkos::fence(); double time_overlapped_reduce = timer.seconds(); - Kokkos::deep_copy(h_result2,result2); - Kokkos::deep_copy(h_result1,result1); + Kokkos::deep_copy(h_result2, result2); + Kokkos::deep_copy(h_result1, result1); - ASSERT_EQ(h_result1(),h_result()); - ASSERT_EQ(h_result2(),h_result()); + ASSERT_EQ(h_result1(), h_result()); + ASSERT_EQ(h_result2(), h_result()); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_overlapped_reduce < 1.5*time_no_overlapped_reduce); - } - printf("Time RangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n",time_no_overlapped_reduce,time_overlapped_reduce); - SpaceInstance::destroy(space1); - SpaceInstance::destroy(space2); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_overlapped_reduce < 1.5 * time_no_overlapped_reduce); + } + printf("Time RangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n", + time_no_overlapped_reduce, time_overlapped_reduce); + SpaceInstance::destroy(space1); + SpaceInstance::destroy(space2); } -TEST_F( default_exec, overlap_mdrange_policy ) { - int N = 200; - int M = 10000; - int R = 10; - - TEST_EXECSPACE space; - TEST_EXECSPACE space1 = SpaceInstance::create(); - TEST_EXECSPACE space2 = SpaceInstance::create(); - - Kokkos::View a("A",N,M); - FunctorMDRange f(M,R,a); - FunctorMDRangeReduce fr(M,R,a); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>({0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorMDRange(M,R,a)); - - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel1", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space1,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel2", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space2,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - Kokkos::Timer timer; - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel3", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel4", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel5", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space1,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorMDRange(M,R,a)); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel6", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space2,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorMDRange(M,R,a)); - Kokkos::fence(); - double time_overlap = timer.seconds(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel7", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel8", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - double time_end = timer.seconds(); - - if(SpaceInstance::overlap()) { - ASSERT_TRUE( (time_end > 1.5*time_overlap) ); - } - printf("Time MDRangePolicy: NonOverlap: %lf Time Overlap: %lf\n",time_end,time_overlap); - - Kokkos::View result("result"); - Kokkos::View result1("result1"); - Kokkos::View result2("result2"); - Kokkos::View h_result("h_result"); - Kokkos::View h_result1("h_result1"); - Kokkos::View h_result2("h_result2"); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::fence(); - double time_fenced = timer.seconds(); - Kokkos::deep_copy(h_result,result); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - double time_not_fenced = timer.seconds(); - Kokkos::fence(); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_fenced>2.0*time_not_fenced); - } - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); +TEST(default_exec, overlap_mdrange_policy) { + int N = 200; + int M = 10000; + int R = 10; + + TEST_EXECSPACE space; + TEST_EXECSPACE space1 = SpaceInstance::create(); + TEST_EXECSPACE space2 = SpaceInstance::create(); + + Kokkos::View a("A", N, M); + FunctorMDRange f(M, R, a); + FunctorMDRangeReduce fr(M, R, a); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel0", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>({0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorMDRange(M, R, a)); + + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel1", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space1, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel2", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space2, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + Kokkos::Timer timer; + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel3", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel4", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel5", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space1, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorMDRange(M, R, a)); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel6", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space2, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorMDRange(M, R, a)); + Kokkos::fence(); + double time_overlap = timer.seconds(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel7", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel8", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + double time_end = timer.seconds(); + + if (SpaceInstance::overlap()) { + ASSERT_TRUE((time_end > 1.5 * time_overlap)); + } + printf("Time MDRangePolicy: NonOverlap: %lf Time Overlap: %lf\n", time_end, + time_overlap); + + Kokkos::View result("result"); + Kokkos::View result1("result1"); + Kokkos::View result2("result2"); + Kokkos::View h_result("h_result"); + Kokkos::View h_result1("h_result1"); + Kokkos::View h_result2("h_result2"); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::fence(); + double time_fenced = timer.seconds(); + Kokkos::deep_copy(h_result, result); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + double time_not_fenced = timer.seconds(); + Kokkos::fence(); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_fenced > 2.0 * time_not_fenced); + } + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); Kokkos::fence(); double time_no_overlapped_reduce = timer.seconds(); - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space1,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result1); - Kokkos::parallel_reduce("default_exec::overlap_mdrange_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::MDRangePolicy>(space2,{0,0},{N,R}), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result2); + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space1, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result1); + Kokkos::parallel_reduce( + "default_exec::overlap_mdrange_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::MDRangePolicy>(space2, {0, 0}, + {N, R}), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result2); Kokkos::fence(); double time_overlapped_reduce = timer.seconds(); - Kokkos::deep_copy(h_result2,result2); - Kokkos::deep_copy(h_result1,result1); - - ASSERT_EQ(h_result1(),h_result()); - ASSERT_EQ(h_result2(),h_result()); + Kokkos::deep_copy(h_result2, result2); + Kokkos::deep_copy(h_result1, result1); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_overlapped_reduce < 1.5*time_no_overlapped_reduce); - } - printf("Time MDRangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n",time_no_overlapped_reduce,time_overlapped_reduce); - SpaceInstance::destroy(space2); - SpaceInstance::destroy(space1); + ASSERT_EQ(h_result1(), h_result()); + ASSERT_EQ(h_result2(), h_result()); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_overlapped_reduce < 1.5 * time_no_overlapped_reduce); + } + printf("Time MDRangePolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n", + time_no_overlapped_reduce, time_overlapped_reduce); + SpaceInstance::destroy(space2); + SpaceInstance::destroy(space1); } -TEST_F( default_exec, overlap_team_policy ) { +TEST(default_exec, overlap_team_policy) { int N = 20; - int M = 1000000; - int R = 10; - - TEST_EXECSPACE space; - TEST_EXECSPACE space1 = SpaceInstance::create(); - TEST_EXECSPACE space2 = SpaceInstance::create(); - - Kokkos::View a("A",N,M); - FunctorTeam f(M,R,a); - FunctorTeamReduce fr(M,R,a); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel0", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorTeam(M,R,a)); - - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel1", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space1,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel2", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space2,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - Kokkos::Timer timer; - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel3", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel4", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel5", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space1,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorTeam(M,R,a)); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel6", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space2,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , FunctorTeam(M,R,a)); - Kokkos::fence(); - double time_overlap = timer.seconds(); - - timer.reset(); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel7", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::parallel_for("default_exec::overlap_range_policy::kernel8", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , f); - Kokkos::fence(); - double time_end = timer.seconds(); - - if(SpaceInstance::overlap()) { - ASSERT_TRUE( (time_end > 1.5*time_overlap) ); - } - printf("Time TeamPolicy: NonOverlap: %lf Time Overlap: %lf\n",time_end,time_overlap); - - Kokkos::View result("result"); - Kokkos::View result1("result1"); - Kokkos::View result2("result2"); - Kokkos::View h_result("h_result"); - Kokkos::View h_result1("h_result1"); - Kokkos::View h_result2("h_result2"); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::fence(); - double time_fenced = timer.seconds(); - Kokkos::deep_copy(h_result,result); - - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - double time_not_fenced = timer.seconds(); - Kokkos::fence(); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_fenced>2.0*time_not_fenced); - } - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result); + int M = 1000000; + int R = 10; + + TEST_EXECSPACE space; + TEST_EXECSPACE space1 = SpaceInstance::create(); + TEST_EXECSPACE space2 = SpaceInstance::create(); + + Kokkos::View a("A", N, M); + FunctorTeam f(M, R, a); + FunctorTeamReduce fr(M, R, a); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel0", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorTeam(M, R, a)); + + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel1", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space1, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel2", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space2, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + Kokkos::Timer timer; + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel3", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel4", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel5", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space1, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorTeam(M, R, a)); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel6", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space2, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + FunctorTeam(M, R, a)); + Kokkos::fence(); + double time_overlap = timer.seconds(); + + timer.reset(); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel7", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::parallel_for( + "default_exec::overlap_range_policy::kernel8", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + f); + Kokkos::fence(); + double time_end = timer.seconds(); + + if (SpaceInstance::overlap()) { + ASSERT_TRUE((time_end > 1.5 * time_overlap)); + } + printf("Time TeamPolicy: NonOverlap: %lf Time Overlap: %lf\n", time_end, + time_overlap); + + Kokkos::View result("result"); + Kokkos::View result1("result1"); + Kokkos::View result2("result2"); + Kokkos::View h_result("h_result"); + Kokkos::View h_result1("h_result1"); + Kokkos::View h_result2("h_result2"); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::fence(); + double time_fenced = timer.seconds(); + Kokkos::deep_copy(h_result, result); + + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + double time_not_fenced = timer.seconds(); + Kokkos::fence(); + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_fenced > 2.0 * time_not_fenced); + } + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result); Kokkos::fence(); double time_no_overlapped_reduce = timer.seconds(); - timer.reset(); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space1,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result1); - Kokkos::parallel_reduce("default_exec::overlap_team_policy::kernel_reduce", - Kokkos::Experimental::require( - Kokkos::TeamPolicy(space2,N,Kokkos::AUTO), - Kokkos::Experimental::WorkItemProperty::HintLightWeight) - , fr, result2); + timer.reset(); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space1, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result1); + Kokkos::parallel_reduce( + "default_exec::overlap_team_policy::kernel_reduce", + Kokkos::Experimental::require( + Kokkos::TeamPolicy(space2, N, Kokkos::AUTO), + Kokkos::Experimental::WorkItemProperty::HintLightWeight), + fr, result2); Kokkos::fence(); double time_overlapped_reduce = timer.seconds(); - Kokkos::deep_copy(h_result2,result2); - Kokkos::deep_copy(h_result1,result1); + Kokkos::deep_copy(h_result2, result2); + Kokkos::deep_copy(h_result1, result1); - ASSERT_EQ(h_result1(),h_result()); - ASSERT_EQ(h_result2(),h_result()); + ASSERT_EQ(h_result1(), h_result()); + ASSERT_EQ(h_result2(), h_result()); - if(SpaceInstance::overlap()) { - ASSERT_TRUE(time_overlapped_reduce < 1.5*time_no_overlapped_reduce); - } - printf("Time TeamPolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n",time_no_overlapped_reduce,time_overlapped_reduce); - SpaceInstance::destroy(space1); - SpaceInstance::destroy(space2); -} + if (SpaceInstance::overlap()) { + ASSERT_TRUE(time_overlapped_reduce < 1.5 * time_no_overlapped_reduce); + } + printf("Time TeamPolicy Reduce: NonOverlap: %lf Time Overlap: %lf\n", + time_no_overlapped_reduce, time_overlapped_reduce); + SpaceInstance::destroy(space1); + SpaceInstance::destroy(space2); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp index 685194c150..550316bec9 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewAllocate.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,102 +49,112 @@ namespace Test { -template +template void run_allocateview_tests(int N, int R) { const int N1 = N; - const int N2 = N*N; - const int N3 = N2*N; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N * N; + const int N3 = N2 * N; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time4,time5,time6,time7,time8,time_raw = 100000.0; + double time1, time2, time3, time4, time5, time6, time7, time8, + time_raw = 100000.0; { Kokkos::Timer timer; - for(int r=0; r a("A1",N8); + for (int r = 0; r < R; r++) { + Kokkos::View a("A1", N8); } - time1 = timer.seconds()/R; + time1 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A2",N4,N4); + for (int r = 0; r < R; r++) { + Kokkos::View a("A2", N4, N4); } - time2 = timer.seconds()/R; + time2 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A3",N3,N3,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A3", N3, N3, N2); } - time3 = timer.seconds()/R; + time3 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A4",N2,N2,N2,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A4", N2, N2, N2, N2); } - time4 = timer.seconds()/R; + time4 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A5",N2,N2,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A5", N2, N2, N1, N1, N2); } - time5 = timer.seconds()/R; + time5 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A6",N2,N1,N1,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); } - time6 = timer.seconds()/R; + time6 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A7",N2,N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); } - time7 = timer.seconds()/R; + time7 = timer.seconds() / R; } { Kokkos::Timer timer; - for(int r=0; r a("A8",N1,N1,N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); } - time8 = timer.seconds()/R; + time8 = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { Kokkos::Timer timer; - for(int r=0;r(10,1); + run_allocateview_tests(10, 1); printf("Create View Performance for LayoutRight:\n"); - run_allocateview_tests(10,1); + run_allocateview_tests(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp index eff31c69bb..8e7bf25e80 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,204 +49,213 @@ namespace Test { -template -double deepcopy_view (ViewTypeA& a, ViewTypeB& b, int repeat){ +template +double deepcopy_view(ViewTypeA& a, ViewTypeB& b, int repeat) { Kokkos::Timer timer; - for(int i=0; i +template void run_deepcopyview_tests123(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N3 = N2*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N3 = N2 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time_raw = 100000.0; + double time1, time2, time3, time_raw = 100000.0; { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - time1 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + time1 = deepcopy_view(a, b, R) / R; } { - Kokkos::View a("A2",N4,N4); - Kokkos::View b("B2",N4,N4); - time2 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A2", N4, N4); + Kokkos::View b("B2", N4, N4); + time2 = deepcopy_view(a, b, R) / R; } { - Kokkos::View a("A3",N3,N3,N2); - Kokkos::View b("B3",N3,N3,N2); - time3 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A3", N3, N3, N2); + Kokkos::View b("B3", N3, N3, N2); + time3 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests45(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time4,time5,time_raw = 100000.0; + double time4, time5, time_raw = 100000.0; { - Kokkos::View a("A4",N2,N2,N2,N2); - Kokkos::View b("B4",N2,N2,N2,N2); - time4 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A4", N2, N2, N2, N2); + Kokkos::View b("B4", N2, N2, N2, N2); + time4 = deepcopy_view(a, b, R) / R; } { - Kokkos::View a("A5",N2,N2,N1,N1,N2); - Kokkos::View b("B5",N2,N2,N1,N1,N2); - time5 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A5", N2, N2, N1, N1, N2); + Kokkos::View b("B5", N2, N2, N1, N1, N2); + time5 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests6(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time6,time_raw = 100000.0; + double time6, time_raw = 100000.0; { - Kokkos::View a("A6",N2,N1,N1,N1,N1,N2); - Kokkos::View b("B6",N2,N1,N1,N1,N1,N2); - time6 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); + Kokkos::View b("B6", N2, N1, N1, N1, N1, N2); + time6 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests7(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time7,time_raw = 100000.0; + double time7, time_raw = 100000.0; { - Kokkos::View a("A7",N2,N1,N1,N1,N1,N1,N1); - Kokkos::View b("B7",N2,N1,N1,N1,N1,N1,N1); - time7 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); + Kokkos::View b("B7", N2, N1, N1, N1, N1, N1, N1); + time7 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_deepcopyview_tests8(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time8,time_raw = 100000.0; + double time8, time_raw = 100000.0; { - Kokkos::View a("A8",N1,N1,N1,N1,N1,N1,N1,N1); - Kokkos::View b("B8",N1,N1,N1,N1,N1,N1,N1,N1); - time8 = deepcopy_view(a,b,R)/R; + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); + Kokkos::View b("B8", N1, N1, N1, N1, N1, N1, N1, + N1); + time8 = deepcopy_view(a, b, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); - Kokkos::View b("B1",N8); - double* const a_ptr = a.data(); + Kokkos::View a("A1", N8); + Kokkos::View b("B1", N8); + double* const a_ptr = a.data(); const double* const b_ptr = b.data(); Kokkos::Timer timer; - for(int r=0;r +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank123 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank123) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp index b7fa71b06f..3f9b694461 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank45 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank45) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp index ee86af41b0..ac364c31cb 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank6 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank6) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp index 5a7a78a196..94f30bac9f 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank7 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank7) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp index cc0d7a6c2a..b916169f1b 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_a8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftLeft_Rank8 ) { +TEST(default_exec, ViewDeepCopy_LeftLeft_Rank8) { printf("DeepCopy Performance for LayoutLeft to LayoutLeft:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp index eb9921d090..f314cb0ff4 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank123 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank123) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp index b805c4c7fc..5d06f060af 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank45 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank45) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp index 8f350f4895..0e28fee631 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank6 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank6) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp index 6f82e178f9..37e1325fc4 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank7 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank7) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp index ef165c9a35..986c39aaf4 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_b8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightRight_Rank8 ) { +TEST(default_exec, ViewDeepCopy_RightRight_Rank8) { printf("DeepCopy Performance for LayoutRight to LayoutRight:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp index ebc924d9f0..b98563ee42 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank123 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank123) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp index a8a7935640..a0ef11e09b 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank45 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank45) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp index c65c17c55b..fea5dde73a 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank6 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank6) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp index 48fcf053e6..a8c8d866f9 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank7 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank7) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp index 46e5798c8f..e5abdaa5d8 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_c8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_LeftRight_Rank8 ) { +TEST(default_exec, ViewDeepCopy_LeftRight_Rank8) { printf("DeepCopy Performance for LayoutLeft to LayoutRight:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp index ad0f455cfc..2b58f8dd1f 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank123 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank123) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests123(10,1); -} + run_deepcopyview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp index 4853e343dd..fe34e4fd1a 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank45 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank45) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests45(10,1); -} + run_deepcopyview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp index 1ce1041458..115b223e68 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank6 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank6) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests6(10,1); -} + run_deepcopyview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp index af73733e64..51e88795e7 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank7 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank7) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests7(10,1); -} + run_deepcopyview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp index 3c9b9934cb..2a53cdef21 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewCopy_d8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,10 +42,10 @@ //@HEADER */ -#include +#include namespace Test { -TEST_F( default_exec, ViewDeepCopy_RightLeft_Rank8 ) { +TEST(default_exec, ViewDeepCopy_RightLeft_Rank8) { printf("DeepCopy Performance for LayoutRight to LayoutLeft:\n"); - run_deepcopyview_tests8(10,1); -} + run_deepcopyview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp index b17356f0c8..38be4bb212 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,186 +49,195 @@ namespace Test { -template -double fill_view (ViewType& a, typename ViewType::const_value_type& val, int repeat){ +template +double fill_view(ViewType& a, typename ViewType::const_value_type& val, + int repeat) { Kokkos::Timer timer; - for(int i=0; i +template void run_fillview_tests123(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N3 = N2*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N3 = N2 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time_raw = 100000.0; + double time1, time2, time3, time_raw = 100000.0; { - Kokkos::View a("A1",N8); - time1 = fill_view(a,1.1,R)/R; + Kokkos::View a("A1", N8); + time1 = fill_view(a, 1.1, R) / R; } { - Kokkos::View a("A2",N4,N4); - time2 = fill_view(a,1.1,R)/R; + Kokkos::View a("A2", N4, N4); + time2 = fill_view(a, 1.1, R) / R; } { - Kokkos::View a("A3",N3,N3,N2); - time3 = fill_view(a,1.1,R)/R; + Kokkos::View a("A3", N3, N3, N2); + time3 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests45(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time4,time5,time_raw = 100000.0; + double time4, time5, time_raw = 100000.0; { - Kokkos::View a("A4",N2,N2,N2,N2); - time4 = fill_view(a,1.1,R)/R; + Kokkos::View a("A4", N2, N2, N2, N2); + time4 = fill_view(a, 1.1, R) / R; } { - Kokkos::View a("A5",N2,N2,N1,N1,N2); - time5 = fill_view(a,1.1,R)/R; + Kokkos::View a("A5", N2, N2, N1, N1, N2); + time5 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests6(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time6,time_raw = 100000.0; + double time6, time_raw = 100000.0; { - Kokkos::View a("A6",N2,N1,N1,N1,N1,N2); - time6 = fill_view(a,1.1,R)/R; + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); + time6 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests7(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time7,time_raw = 100000.0; + double time7, time_raw = 100000.0; { - Kokkos::View a("A7",N2,N1,N1,N1,N1,N1,N1); - time7 = fill_view(a,1.1,R)/R; + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); + time7 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r +template void run_fillview_tests8(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time8,time_raw = 100000.0; + double time8, time_raw = 100000.0; { - Kokkos::View a("A8",N1,N1,N1,N1,N1,N1,N1,N1); - time8 = fill_view(a,1.1,R)/R; + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); + time8 = fill_view(a, 1.1, R) / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r namespace Test { -TEST_F( default_exec, ViewFill_Rank123 ) { +TEST(default_exec, ViewFill_Rank123) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests123(10,1); + run_fillview_tests123(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests123(10,1); -} + run_fillview_tests123(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp index e1d1b6900d..53ac509da8 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank45 ) { +TEST(default_exec, ViewFill_Rank45) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests45(10,1); + run_fillview_tests45(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests45(10,1); -} + run_fillview_tests45(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp index 571867937e..f0a2e248f2 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank6 ) { +TEST(default_exec, ViewFill_Rank6) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests6(10,1); + run_fillview_tests6(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests6(10,1); -} + run_fillview_tests6(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp index 9b89c8fc7b..675d9e636f 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank7 ) { +TEST(default_exec, ViewFill_Rank7) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests7(10,1); + run_fillview_tests7(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests7(10,1); -} + run_fillview_tests7(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp index 4d3df50354..35e1e81c43 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewFill_8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,10 +45,10 @@ #include namespace Test { -TEST_F( default_exec, ViewFill_Rank8 ) { +TEST(default_exec, ViewFill_Rank8) { printf("ViewFill Performance for LayoutLeft:\n"); - run_fillview_tests8(10,1); + run_fillview_tests8(10, 1); printf("ViewFill Performance for LayoutRight:\n"); - run_fillview_tests8(10,1); -} + run_fillview_tests8(10, 1); } +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp index b5019b467a..2ea81b5046 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,230 +49,340 @@ namespace Test { -template +template void run_resizeview_tests123(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N3 = N2*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N3 = N2 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time1,time2,time3,time_raw = 100000.0; + double time1, time2, time3, time_raw = 100000.0; + double time1_noinit, time2_noinit, time3_noinit; { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N8 * 1.1)); } - time1 = timer.seconds()/R; + time1 = timer.seconds() / R; } { - Kokkos::View a("A2",N4,N4); + Kokkos::View a("A2", N4, N4); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N4*1.1),N4); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N4 * 1.1), N4); } - time2 = timer.seconds()/R; + time2 = timer.seconds() / R; } { - Kokkos::View a("A3",N3,N3,N2); + Kokkos::View a("A3", N3, N3, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N3*1.1),N3,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N3 * 1.1), N3, N2); } - time3 = timer.seconds()/R; + time3 = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N8 * 1.1)); + } + time1_noinit = timer.seconds() / R; + } + { + Kokkos::View a("A2", N4, N4); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N4 * 1.1), N4); + } + time2_noinit = timer.seconds() / R; + } + { + Kokkos::View a("A3", N3, N3, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N3 * 1.1), N3, N2); + } + time3_noinit = timer.seconds() / R; + } +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + { + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank1: %lf s %lf MB %lf GB/s\n",time1,size,2.0*size/1024/time1); - printf(" Rank2: %lf s %lf MB %lf GB/s\n",time2,size,2.0*size/1024/time2); - printf(" Rank3: %lf s %lf MB %lf GB/s\n",time3,size,2.0*size/1024/time3); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank1: %lf s %lf MB %lf GB/s\n", time1, size, + 2.0 * size / 1024 / time1); + printf(" Rank2: %lf s %lf MB %lf GB/s\n", time2, size, + 2.0 * size / 1024 / time2); + printf(" Rank3: %lf s %lf MB %lf GB/s\n", time3, size, + 2.0 * size / 1024 / time3); + printf(" Rank1 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time1_noinit, size, 2.0 * size / 1024 / time1_noinit); + printf(" Rank2 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time2_noinit, size, 2.0 * size / 1024 / time2_noinit); + printf(" Rank3 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time3_noinit, size, 2.0 * size / 1024 / time3_noinit); } -template +template void run_resizeview_tests45(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time4,time5,time_raw = 100000.0; + double time4, time5, time_raw = 100000.0; + double time4_noinit, time5_noinit; + { + Kokkos::View a("A4", N2, N2, N2, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N2, N2, N2); + } + time4 = timer.seconds() / R; + } { - Kokkos::View a("A4",N2,N2,N2,N2); + Kokkos::View a("A5", N2, N2, N1, N1, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N2,N2,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N2, N1, N1, N2); } - time4 = timer.seconds()/R; + time5 = timer.seconds() / R; } { - Kokkos::View a("A5",N2,N2,N1,N1,N2); + Kokkos::View a("A4", N2, N2, N2, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N2,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N2, N2, + N2); } - time5 = timer.seconds()/R; + time4_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A5", N2, N2, N1, N1, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N2, N1, N1, + N2); + } + time5_noinit = timer.seconds() / R; + } +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) + { + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank4: %lf s %lf MB %lf GB/s\n",time4,size,2.0*size/1024/time4); - printf(" Rank5: %lf s %lf MB %lf GB/s\n",time5,size,2.0*size/1024/time5); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank4: %lf s %lf MB %lf GB/s\n", time4, size, + 2.0 * size / 1024 / time4); + printf(" Rank5: %lf s %lf MB %lf GB/s\n", time5, size, + 2.0 * size / 1024 / time5); + printf(" Rank4 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time4_noinit, size, 2.0 * size / 1024 / time4_noinit); + printf(" Rank5 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time5_noinit, size, 2.0 * size / 1024 / time5_noinit); } -template +template void run_resizeview_tests6(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time6,time_raw = 100000.0; + double time6, time6_noinit, time_raw = 100000.0; + { + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N1, N1, N1, N1, N2); + } + time6 = timer.seconds() / R; + } { - Kokkos::View a("A6",N2,N1,N1,N1,N1,N2); + Kokkos::View a("A6", N2, N1, N1, N1, N1, N2); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N1,N1,N1,N1,N2); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N1, N1, N1, + N1, N2); } - time6 = timer.seconds()/R; + time6_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank6: %lf s %lf MB %lf GB/s\n",time6,size,2.0*size/1024/time6); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank6: %lf s %lf MB %lf GB/s\n", time6, size, + 2.0 * size / 1024 / time6); + printf(" Rank6 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time6_noinit, size, 2.0 * size / 1024 / time6_noinit); } -template +template void run_resizeview_tests7(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time7,time_raw = 100000.0; + double time7, time7_noinit, time_raw = 100000.0; + { + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N2 * 1.1), N1, N1, N1, N1, N1, N1); + } + time7 = timer.seconds() / R; + } { - Kokkos::View a("A7",N2,N1,N1,N1,N1,N1,N1); + Kokkos::View a("A7", N2, N1, N1, N1, N1, N1, N1); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N2*1.1),N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N2 * 1.1), N1, N1, N1, + N1, N1, N1); } - time7 = timer.seconds()/R; + time7_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank7: %lf s %lf MB %lf GB/s\n",time7,size,2.0*size/1024/time7); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank7: %lf s %lf MB %lf GB/s\n", time7, size, + 2.0 * size / 1024 / time7); + printf(" Rank7 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time7_noinit, size, 2.0 * size / 1024 / time7_noinit); } -template +template void run_resizeview_tests8(int N, int R) { const int N1 = N; - const int N2 = N1*N1; - const int N4 = N2*N2; - const int N8 = N4*N4; + const int N2 = N1 * N1; + const int N4 = N2 * N2; + const int N8 = N4 * N4; - double time8,time_raw = 100000.0; + double time8, time8_noinit, time_raw = 100000.0; + { + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); + Kokkos::Timer timer; + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(a_, int(N1 * 1.1), N1, N1, N1, N1, N1, N1, N1); + } + time8 = timer.seconds() / R; + } { - Kokkos::View a("A8",N1,N1,N1,N1,N1,N1,N1,N1); + Kokkos::View a("A8", N1, N1, N1, N1, N1, N1, N1, + N1); Kokkos::Timer timer; - for(int r=0; r a_(a); - Kokkos::resize(a_,int(N1*1.1),N1,N1,N1,N1,N1,N1,N1); + for (int r = 0; r < R; r++) { + Kokkos::View a_(a); + Kokkos::resize(Kokkos::WithoutInitializing, a_, int(N1 * 1.1), N1, N1, N1, + N1, N1, N1, N1); } - time8 = timer.seconds()/R; + time8_noinit = timer.seconds() / R; } - #if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) +#if defined(KOKKOS_ENABLE_CUDA_LAMBDA) || !defined(KOKKOS_ENABLE_CUDA) { - Kokkos::View a("A1",N8); + Kokkos::View a("A1", N8); double* a_ptr = a.data(); Kokkos::Timer timer; - for(int r=0;r a1(Kokkos::ViewAllocateWithoutInitializing("A1"),int(N8*1.1)); + for (int r = 0; r < R; r++) { + Kokkos::View a1( + Kokkos::ViewAllocateWithoutInitializing("A1"), int(N8 * 1.1)); double* a1_ptr = a1.data(); - Kokkos::parallel_for(N8, KOKKOS_LAMBDA (const int& i) { - a1_ptr[i] = a_ptr[i]; - }); + Kokkos::parallel_for( + N8, KOKKOS_LAMBDA(const int& i) { a1_ptr[i] = a_ptr[i]; }); Kokkos::fence(); } Kokkos::fence(); - time_raw = timer.seconds()/R; + time_raw = timer.seconds() / R; } - #endif - double size = 1.0*N8*8/1024/1024; - printf(" Raw: %lf s %lf MB %lf GB/s\n",time_raw,size,2.0*size/1024/time_raw); - printf(" Rank8: %lf s %lf MB %lf GB/s\n",time8,size,2.0*size/1024/time8); +#endif + double size = 1.0 * N8 * 8 / 1024 / 1024; + printf(" Raw: %lf s %lf MB %lf GB/s\n", time_raw, size, + 2.0 * size / 1024 / time_raw); + printf(" Rank8: %lf s %lf MB %lf GB/s\n", time8, size, + 2.0 * size / 1024 / time8); + printf(" Rank8 (WithoutInitializing): %lf s %lf MB %lf GB/s\n", + time8_noinit, size, 2.0 * size / 1024 / time8_noinit); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp index 61b7edf373..1dc4f285f5 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_123.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank123 ) { +TEST(default_exec, ViewResize_Rank123) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests123(10,1); + run_resizeview_tests123(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests123(10,1); + run_resizeview_tests123(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp index 172f9474d9..3754a5bb14 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_45.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank_45 ) { +TEST(default_exec, ViewResize_Rank_45) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests45(10,1); + run_resizeview_tests45(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests45(10,1); + run_resizeview_tests45(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp index d4f8fb2af0..1b8d6fbc8a 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_6.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank6 ) { +TEST(default_exec, ViewResize_Rank6) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests6(10,1); + run_resizeview_tests6(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests6(10,1); + run_resizeview_tests6(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp index f7b9b5b545..f8efa195fc 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_7.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank7 ) { +TEST(default_exec, ViewResize_Rank7) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests7(10,1); + run_resizeview_tests7(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests7(10,1); + run_resizeview_tests7(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp b/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp index 877fcef933..afeeb64356 100644 --- a/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp +++ b/lib/kokkos/core/perf_test/PerfTest_ViewResize_8.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,11 +46,11 @@ namespace Test { -TEST_F( default_exec, ViewResize_Rank8 ) { +TEST(default_exec, ViewResize_Rank8) { printf("Resize View Performance for LayoutLeft:\n"); - run_resizeview_tests8(10,1); + run_resizeview_tests8(10, 1); printf("Resize View Performance for LayoutRight:\n"); - run_resizeview_tests8(10,1); + run_resizeview_tests8(10, 1); } -} +} // namespace Test diff --git a/lib/kokkos/core/perf_test/test_atomic.cpp b/lib/kokkos/core/perf_test/test_atomic.cpp index 24e4f015d3..7699d7b91c 100644 --- a/lib/kokkos/core/perf_test/test_atomic.cpp +++ b/lib/kokkos/core/perf_test/test_atomic.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -50,335 +51,323 @@ typedef Kokkos::DefaultExecutionSpace exec_space; -#define RESET 0 -#define BRIGHT 1 -#define DIM 2 -#define UNDERLINE 3 -#define BLINK 4 -#define REVERSE 7 -#define HIDDEN 8 - -#define BLACK 0 -#define RED 1 -#define GREEN 2 -#define YELLOW 3 -#define BLUE 4 -#define MAGENTA 5 -#define CYAN 6 -#define GREY 7 -#define WHITE 8 - -void textcolor(int attr, int fg, int bg) -{ char command[40]; - - /* Command is the control command to the terminal */ - sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); - printf("%s", command); +#define RESET 0 +#define BRIGHT 1 +#define DIM 2 +#define UNDERLINE 3 +#define BLINK 4 +#define REVERSE 7 +#define HIDDEN 8 + +#define BLACK 0 +#define RED 1 +#define GREEN 2 +#define YELLOW 3 +#define BLUE 4 +#define MAGENTA 5 +#define CYAN 6 +#define GREY 7 +#define WHITE 8 + +void textcolor(int attr, int fg, int bg) { + char command[40]; + + /* Command is the control command to the terminal */ + sprintf(command, "%c[%d;%d;%dm", 0x1B, attr, fg + 30, bg + 40); + printf("%s", command); } -void textcolor_standard() {textcolor(RESET, BLACK, WHITE);} +void textcolor_standard() { textcolor(RESET, BLACK, WHITE); } - -template -struct ZeroFunctor{ +template +struct ZeroFunctor { typedef DEVICE_TYPE execution_space; - typedef typename Kokkos::View type; - typedef typename Kokkos::View::HostMirror h_type; + typedef typename Kokkos::View type; + typedef typename Kokkos::View::HostMirror h_type; type data; KOKKOS_INLINE_FUNCTION - void operator()(int) const { - data() = 0; - } + void operator()(int) const { data() = 0; } }; //--------------------------------------------------- //--------------atomic_fetch_add--------------------- //--------------------------------------------------- -template -struct AddFunctor{ +template +struct AddFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION - void operator()(int) const { - Kokkos::atomic_fetch_add(&data(),(T)1); - } + void operator()(int) const { Kokkos::atomic_fetch_add(&data(), (T)1); } }; -template +template T AddLoop(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct AddFunctor f_add; + struct AddFunctor f_add; f_add.data = data; - Kokkos::parallel_for(loop,f_add); + Kokkos::parallel_for(loop, f_add); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template -struct AddNonAtomicFunctor{ +template +struct AddNonAtomicFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION - void operator()(int) const { - data()+=(T)1; - } + void operator()(int) const { data() += (T)1; } }; -template +template T AddLoopNonAtomic(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct AddNonAtomicFunctor f_add; + struct AddNonAtomicFunctor f_add; f_add.data = data; - Kokkos::parallel_for(loop,f_add); + Kokkos::parallel_for(loop, f_add); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template +template T AddLoopSerial(int loop) { T* data = new T[1]; data[0] = 0; - for(int i=0;i -struct CASFunctor{ +template +struct CASFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { - T old = data(); - T newval, assumed; - do { - assumed = old; - newval = assumed + (T)1; - old = Kokkos::atomic_compare_exchange(&data(), assumed, newval); - } - while( old != assumed ); + T old = data(); + T newval, assumed; + do { + assumed = old; + newval = assumed + (T)1; + old = Kokkos::atomic_compare_exchange(&data(), assumed, newval); + } while (old != assumed); } }; -template +template T CASLoop(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct CASFunctor f_cas; + struct CASFunctor f_cas; f_cas.data = data; - Kokkos::parallel_for(loop,f_cas); + Kokkos::parallel_for(loop, f_cas); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template -struct CASNonAtomicFunctor{ +template +struct CASNonAtomicFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data; KOKKOS_INLINE_FUNCTION void operator()(int) const { - volatile T assumed; - volatile T newval; - bool fail=1; - do { - assumed = data(); - newval = assumed + (T)1; - if(data()==assumed) { - data() = newval; - fail = 0; - } - } - while(fail); + volatile T assumed; + volatile T newval; + bool fail = 1; + do { + assumed = data(); + newval = assumed + (T)1; + if (data() == assumed) { + data() = newval; + fail = 0; + } + } while (fail); } }; -template +template T CASLoopNonAtomic(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct CASNonAtomicFunctor f_cas; + struct CASNonAtomicFunctor f_cas; f_cas.data = data; - Kokkos::parallel_for(loop,f_cas); + Kokkos::parallel_for(loop, f_cas); exec_space().fence(); - Kokkos::deep_copy(h_data,data); + Kokkos::deep_copy(h_data, data); T val = h_data(); return val; } -template +template T CASLoopSerial(int loop) { T* data = new T[1]; data[0] = 0; - for(int i=0;i -struct ExchFunctor{ +template +struct ExchFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data, data2; KOKKOS_INLINE_FUNCTION void operator()(int i) const { - T old = Kokkos::atomic_exchange(&data(),(T)i); - Kokkos::atomic_fetch_add(&data2(),old); + T old = Kokkos::atomic_exchange(&data(), (T)i); + Kokkos::atomic_fetch_add(&data2(), old); } }; -template +template T ExchLoop(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - typename ZeroFunctor::type data2("Data"); - typename ZeroFunctor::h_type h_data2("HData"); + typename ZeroFunctor::type data2("Data"); + typename ZeroFunctor::h_type h_data2("HData"); f_zero.data = data2; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct ExchFunctor f_exch; - f_exch.data = data; + struct ExchFunctor f_exch; + f_exch.data = data; f_exch.data2 = data2; - Kokkos::parallel_for(loop,f_exch); + Kokkos::parallel_for(loop, f_exch); exec_space().fence(); - Kokkos::deep_copy(h_data,data); - Kokkos::deep_copy(h_data2,data2); + Kokkos::deep_copy(h_data, data); + Kokkos::deep_copy(h_data2, data2); T val = h_data() + h_data2(); return val; } -template -struct ExchNonAtomicFunctor{ +template +struct ExchNonAtomicFunctor { typedef DEVICE_TYPE execution_space; - typedef Kokkos::View type; + typedef Kokkos::View type; type data, data2; KOKKOS_INLINE_FUNCTION void operator()(int i) const { - T old = data(); - data()=(T) i; - data2()+=old; + T old = data(); + data() = (T)i; + data2() += old; } }; - -template +template T ExchLoopNonAtomic(int loop) { - struct ZeroFunctor f_zero; - typename ZeroFunctor::type data("Data"); - typename ZeroFunctor::h_type h_data("HData"); + struct ZeroFunctor f_zero; + typename ZeroFunctor::type data("Data"); + typename ZeroFunctor::h_type h_data("HData"); f_zero.data = data; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - typename ZeroFunctor::type data2("Data"); - typename ZeroFunctor::h_type h_data2("HData"); + typename ZeroFunctor::type data2("Data"); + typename ZeroFunctor::h_type h_data2("HData"); f_zero.data = data2; - Kokkos::parallel_for(1,f_zero); + Kokkos::parallel_for(1, f_zero); exec_space().fence(); - struct ExchNonAtomicFunctor f_exch; - f_exch.data = data; + struct ExchNonAtomicFunctor f_exch; + f_exch.data = data; f_exch.data2 = data2; - Kokkos::parallel_for(loop,f_exch); + Kokkos::parallel_for(loop, f_exch); exec_space().fence(); - Kokkos::deep_copy(h_data,data); - Kokkos::deep_copy(h_data2,data2); + Kokkos::deep_copy(h_data, data); + Kokkos::deep_copy(h_data2, data2); T val = h_data() + h_data2(); return val; } -template +template T ExchLoopSerial(int loop) { - T* data = new T[1]; + T* data = new T[1]; T* data2 = new T[1]; - data[0] = 0; + data[0] = 0; data2[0] = 0; - for(int i=0;i +template T LoopVariant(int loop, int test) { switch (test) { case 1: return AddLoop(loop); @@ -388,7 +377,7 @@ T LoopVariant(int loop, int test) { return 0; } -template +template T LoopVariantSerial(int loop, int test) { switch (test) { case 1: return AddLoopSerial(loop); @@ -398,7 +387,7 @@ T LoopVariantSerial(int loop, int test) { return 0; } -template +template T LoopVariantNonAtomic(int loop, int test) { switch (test) { case 1: return AddLoopNonAtomic(loop); @@ -408,100 +397,105 @@ T LoopVariantNonAtomic(int loop, int test) { return 0; } -template +template void Loop(int loop, int test, const char* type_name) { - LoopVariant(loop,test); + LoopVariant(loop, test); Kokkos::Impl::Timer timer; - T res = LoopVariant(loop,test); + T res = LoopVariant(loop, test); double time = timer.seconds(); timer.reset(); - T resNonAtomic = LoopVariantNonAtomic(loop,test); + T resNonAtomic = LoopVariantNonAtomic(loop, test); double timeNonAtomic = timer.seconds(); timer.reset(); - T resSerial = LoopVariantSerial(loop,test); + T resSerial = LoopVariantSerial(loop, test); double timeSerial = timer.seconds(); - time *=1e6/loop; - timeNonAtomic*=1e6/loop; - timeSerial *=1e6/loop; - //textcolor_standard(); + time *= 1e6 / loop; + timeNonAtomic *= 1e6 / loop; + timeSerial *= 1e6 / loop; + // textcolor_standard(); bool passed = true; - if(resSerial!=res) passed = false; - //if(!passed) textcolor(RESET,BLACK,YELLOW); - printf("%s Test %i %s --- Loop: %i Value (S,A,NA): %e %e %e Time: %7.4e %7.4e %7.4e Size of Type %i)", - type_name,test,passed?"PASSED":"FAILED",loop, - 1.0*resSerial,1.0*res,1.0*resNonAtomic, - timeSerial,time,timeNonAtomic,(int)sizeof(T)); - //if(!passed) textcolor_standard(); + if (resSerial != res) passed = false; + // if(!passed) textcolor(RESET,BLACK,YELLOW); + printf( + "%s Test %i %s --- Loop: %i Value (S,A,NA): %e %e %e Time: %7.4e %7.4e " + "%7.4e Size of Type %i)", + type_name, test, passed ? "PASSED" : "FAILED", loop, 1.0 * resSerial, + 1.0 * res, 1.0 * resNonAtomic, timeSerial, time, timeNonAtomic, + (int)sizeof(T)); + // if(!passed) textcolor_standard(); printf("\n"); } - -template +template void Test(int loop, int test, const char* type_name) { - if(test==-1) { - Loop(loop,1,type_name); - Loop(loop,2,type_name); - Loop(loop,3,type_name); + if (test == -1) { + Loop(loop, 1, type_name); + Loop(loop, 2, type_name); + Loop(loop, 3, type_name); - } - else - Loop(loop,test,type_name); + } else + Loop(loop, test, type_name); } -int main(int argc, char* argv[]) -{ +int main(int argc, char* argv[]) { int type = -1; int loop = 100000; int test = -1; - for(int i=0;i(loop,test,"int "); + if (type == -1) all_tests = true; + while (type < 100) { + if (type == 1) { + Test(loop, test, "int "); } - if(type==2) { - Test(loop,test,"long int "); + if (type == 2) { + Test(loop, test, "long int "); } - if(type==3) { - Test(loop,test,"long long int "); + if (type == 3) { + Test(loop, test, "long long int "); } - if(type==4) { - Test(loop,test,"unsigned int "); + if (type == 4) { + Test(loop, test, "unsigned int "); } - if(type==5) { - Test(loop,test,"unsigned long int "); + if (type == 5) { + Test(loop, test, "unsigned long int "); } - if(type==6) { - Test(loop,test,"unsigned long long int "); + if (type == 6) { + Test(loop, test, "unsigned long long int "); } - if(type==10) { - //Test(loop,test,"float "); + if (type == 10) { + // Test(loop,test,"float "); } - if(type==11) { - Test(loop,test,"double "); + if (type == 11) { + Test(loop, test, "double "); } - if(!all_tests) type=100; - else type++; + if (!all_tests) + type = 100; + else + type++; } Kokkos::finalize(); - } - diff --git a/lib/kokkos/core/perf_test/test_mempool.cpp b/lib/kokkos/core/perf_test/test_mempool.cpp index c47730ec69..ad8622e7a6 100644 --- a/lib/kokkos/core/perf_test/test_mempool.cpp +++ b/lib/kokkos/core/perf_test/test_mempool.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,310 +50,271 @@ #include #include -using ExecSpace = Kokkos::DefaultExecutionSpace ; -using MemorySpace = Kokkos::DefaultExecutionSpace::memory_space ; +using ExecSpace = Kokkos::DefaultExecutionSpace; +using MemorySpace = Kokkos::DefaultExecutionSpace::memory_space; -using MemoryPool = Kokkos::MemoryPool< ExecSpace > ; +using MemoryPool = Kokkos::MemoryPool; struct TestFunctor { - - typedef Kokkos::View< uintptr_t * , ExecSpace > ptrs_type ; + typedef Kokkos::View ptrs_type; enum : unsigned { chunk = 32 }; - MemoryPool pool ; - ptrs_type ptrs ; - unsigned chunk_span ; - unsigned fill_stride ; - unsigned range_iter ; - unsigned repeat_inner ; - - TestFunctor( size_t total_alloc_size - , unsigned min_superblock_size - , unsigned number_alloc - , unsigned arg_stride_alloc - , unsigned arg_chunk_span - , unsigned arg_repeat ) - : pool() - , ptrs() - , chunk_span(0) - , fill_stride(0) - , repeat_inner(0) - { - MemorySpace m ; - - const unsigned min_block_size = chunk ; - const unsigned max_block_size = chunk * arg_chunk_span ; - pool = MemoryPool( m , total_alloc_size - , min_block_size - , max_block_size - , min_superblock_size ); - - ptrs = ptrs_type( Kokkos::view_alloc( m , "ptrs") , number_alloc ); - fill_stride = arg_stride_alloc ; - chunk_span = arg_chunk_span ; - range_iter = fill_stride * number_alloc ; - repeat_inner = arg_repeat ; - } + MemoryPool pool; + ptrs_type ptrs; + unsigned chunk_span; + unsigned fill_stride; + unsigned range_iter; + unsigned repeat_inner; + + TestFunctor(size_t total_alloc_size, unsigned min_superblock_size, + unsigned number_alloc, unsigned arg_stride_alloc, + unsigned arg_chunk_span, unsigned arg_repeat) + : pool(), ptrs(), chunk_span(0), fill_stride(0), repeat_inner(0) { + MemorySpace m; + + const unsigned min_block_size = chunk; + const unsigned max_block_size = chunk * arg_chunk_span; + pool = MemoryPool(m, total_alloc_size, min_block_size, max_block_size, + min_superblock_size); + + ptrs = ptrs_type(Kokkos::view_alloc(m, "ptrs"), number_alloc); + fill_stride = arg_stride_alloc; + chunk_span = arg_chunk_span; + range_iter = fill_stride * number_alloc; + repeat_inner = arg_repeat; + } //---------------------------------------- - typedef long value_type ; + typedef long value_type; //---------------------------------------- struct TagFill {}; KOKKOS_INLINE_FUNCTION - void operator()( TagFill , int i , value_type & update ) const noexcept - { - if ( 0 == i % fill_stride ) { + void operator()(TagFill, int i, value_type& update) const noexcept { + if (0 == i % fill_stride) { + const int j = i / fill_stride; - const int j = i / fill_stride ; + const unsigned size_alloc = chunk * (1 + (j % chunk_span)); - const unsigned size_alloc = chunk * ( 1 + ( j % chunk_span ) ); + ptrs(j) = (uintptr_t)pool.allocate(size_alloc); - ptrs(j) = (uintptr_t) pool.allocate(size_alloc); - - if ( ptrs(j) ) ++update ; - } + if (ptrs(j)) ++update; } + } - bool test_fill() - { - typedef Kokkos::RangePolicy< ExecSpace , TagFill > policy ; + bool test_fill() { + typedef Kokkos::RangePolicy policy; - long result = 0 ; + long result = 0; - Kokkos::parallel_reduce( policy(0,range_iter), *this , result ); + Kokkos::parallel_reduce(policy(0, range_iter), *this, result); - if ( result == long(ptrs.extent(0)) ) return true; - pool.print_state( std::cerr ); - return false; - } + if (result == long(ptrs.extent(0))) return true; + pool.print_state(std::cerr); + return false; + } //---------------------------------------- struct TagDel {}; KOKKOS_INLINE_FUNCTION - void operator()( TagDel , int i ) const noexcept - { - if ( 0 == i % fill_stride ) { - - const int j = i / fill_stride ; + void operator()(TagDel, int i) const noexcept { + if (0 == i % fill_stride) { + const int j = i / fill_stride; - const unsigned size_alloc = chunk * ( 1 + ( j % chunk_span ) ); + const unsigned size_alloc = chunk * (1 + (j % chunk_span)); - pool.deallocate( (void*) ptrs(j) , size_alloc ); - } + pool.deallocate((void*)ptrs(j), size_alloc); } + } - void test_del() - { - typedef Kokkos::RangePolicy< ExecSpace , TagDel > policy ; + void test_del() { + typedef Kokkos::RangePolicy policy; - Kokkos::parallel_for( policy(0,range_iter), *this ); - Kokkos::fence(); - } + Kokkos::parallel_for(policy(0, range_iter), *this); + Kokkos::fence(); + } //---------------------------------------- struct TagAllocDealloc {}; KOKKOS_INLINE_FUNCTION - void operator()( TagAllocDealloc , int i , long & update ) const noexcept - { - if ( 0 == i % fill_stride ) { - - const int j = i / fill_stride ; - - if ( 0 == j % 3 ) { + void operator()(TagAllocDealloc, int i, long& update) const noexcept { + if (0 == i % fill_stride) { + const int j = i / fill_stride; - for ( unsigned k = 0 ; k < repeat_inner ; ++k ) { + if (0 == j % 3) { + for (unsigned k = 0; k < repeat_inner; ++k) { + const unsigned size_alloc = chunk * (1 + (j % chunk_span)); - const unsigned size_alloc = chunk * ( 1 + ( j % chunk_span ) ); + pool.deallocate((void*)ptrs(j), size_alloc); - pool.deallocate( (void*) ptrs(j) , size_alloc ); + ptrs(j) = (uintptr_t)pool.allocate(size_alloc); - ptrs(j) = (uintptr_t) pool.allocate(size_alloc); - - if ( 0 == ptrs(j) ) update++ ; - } + if (0 == ptrs(j)) update++; } } } + } - bool test_alloc_dealloc() - { - typedef Kokkos::RangePolicy< ExecSpace , TagAllocDealloc > policy ; + bool test_alloc_dealloc() { + typedef Kokkos::RangePolicy policy; - long error_count = 0 ; + long error_count = 0; - Kokkos::parallel_reduce( policy(0,range_iter), *this , error_count ); + Kokkos::parallel_reduce(policy(0, range_iter), *this, error_count); - return 0 == error_count ; - } + return 0 == error_count; + } }; +int main(int argc, char* argv[]) { + static const char help_flag[] = "--help"; + static const char alloc_size_flag[] = "--alloc_size="; + static const char super_size_flag[] = "--super_size="; + static const char chunk_span_flag[] = "--chunk_span="; + static const char fill_stride_flag[] = "--fill_stride="; + static const char fill_level_flag[] = "--fill_level="; + static const char repeat_outer_flag[] = "--repeat_outer="; + static const char repeat_inner_flag[] = "--repeat_inner="; + long total_alloc_size = 1000000; + int min_superblock_size = 10000; + int chunk_span = 5; + int fill_stride = 1; + int fill_level = 70; + int repeat_outer = 1; + int repeat_inner = 1; -int main( int argc , char* argv[] ) -{ - static const char help_flag[] = "--help" ; - static const char alloc_size_flag[] = "--alloc_size=" ; - static const char super_size_flag[] = "--super_size=" ; - static const char chunk_span_flag[] = "--chunk_span=" ; - static const char fill_stride_flag[] = "--fill_stride=" ; - static const char fill_level_flag[] = "--fill_level=" ; - static const char repeat_outer_flag[] = "--repeat_outer=" ; - static const char repeat_inner_flag[] = "--repeat_inner=" ; - - long total_alloc_size = 1000000 ; - int min_superblock_size = 10000 ; - int chunk_span = 5 ; - int fill_stride = 1 ; - int fill_level = 70 ; - int repeat_outer = 1 ; - int repeat_inner = 1 ; - - int ask_help = 0 ; + int ask_help = 0; - for(int i=1;i> actual_superblock_bytes_lg2; + auto superblock_mask = actual_superblock_bytes - 1; + auto nsuperblocks = + (total_alloc_size + superblock_mask) >> actual_superblock_bytes_lg2; auto actual_total_bytes = nsuperblocks * actual_superblock_bytes; - auto bytes_wanted = (actual_total_bytes * fill_level) / 100; - auto chunk_spans = bytes_wanted / chunk_span_bytes; - auto number_alloc = int( chunk_spans * chunk_span ); + auto bytes_wanted = (actual_total_bytes * fill_level) / 100; + auto chunk_spans = bytes_wanted / chunk_span_bytes; + auto number_alloc = int(chunk_spans * chunk_span); - if ( ask_help ) { + if (ask_help) { std::cout << "command line options:" - << " " << help_flag - << " " << alloc_size_flag << "##" + << " " << help_flag << " " << alloc_size_flag << "##" << " " << super_size_flag << "##" << " " << fill_stride_flag << "##" << " " << fill_level_flag << "##" << " " << chunk_span_flag << "##" << " " << repeat_outer_flag << "##" - << " " << repeat_inner_flag << "##" - << std::endl ; + << " " << repeat_inner_flag << "##" << std::endl; return 0; } - Kokkos::initialize(argc,argv); + Kokkos::initialize(argc, argv); - double sum_fill_time = 0; + double sum_fill_time = 0; double sum_cycle_time = 0; - double sum_both_time = 0; - double min_fill_time = std::numeric_limits::max(); + double sum_both_time = 0; + double min_fill_time = std::numeric_limits::max(); double min_cycle_time = std::numeric_limits::max(); - double min_both_time = std::numeric_limits::max(); - //one alloc in fill, alloc/dealloc pair in repeat_inner - for ( int i = 0 ; i < repeat_outer ; ++i ) { + double min_both_time = std::numeric_limits::max(); + // one alloc in fill, alloc/dealloc pair in repeat_inner + for (int i = 0; i < repeat_outer; ++i) { + TestFunctor functor(total_alloc_size, min_superblock_size, number_alloc, + fill_stride, chunk_span, repeat_inner); - TestFunctor functor( total_alloc_size - , min_superblock_size - , number_alloc - , fill_stride - , chunk_span - , repeat_inner ); + Kokkos::Impl::Timer timer; - Kokkos::Impl::Timer timer ; - - if ( ! functor.test_fill() ) { + if (!functor.test_fill()) { Kokkos::abort("fill "); } auto t0 = timer.seconds(); - if ( ! functor.test_alloc_dealloc() ) { + if (!functor.test_alloc_dealloc()) { Kokkos::abort("alloc/dealloc "); } - auto t1 = timer.seconds(); - auto this_fill_time = t0; + auto t1 = timer.seconds(); + auto this_fill_time = t0; auto this_cycle_time = t1 - t0; - auto this_both_time = t1; + auto this_both_time = t1; sum_fill_time += this_fill_time; sum_cycle_time += this_cycle_time; sum_both_time += this_both_time; - min_fill_time = std::min(min_fill_time, this_fill_time); + min_fill_time = std::min(min_fill_time, this_fill_time); min_cycle_time = std::min(min_cycle_time, this_cycle_time); - min_both_time = std::min(min_both_time, this_both_time); + min_both_time = std::min(min_both_time, this_both_time); } Kokkos::finalize(); - printf( "\"mempool: alloc super stride level span inner outer number\" %ld %d %d %d %d %d %d %d\n" - , total_alloc_size - , min_superblock_size - , fill_stride - , fill_level - , chunk_span - , repeat_inner - , repeat_outer - , number_alloc ); - - auto avg_fill_time = sum_fill_time / repeat_outer; + printf( + "\"mempool: alloc super stride level span inner outer number\" %ld %d %d " + "%d %d %d %d %d\n", + total_alloc_size, min_superblock_size, fill_stride, fill_level, + chunk_span, repeat_inner, repeat_outer, number_alloc); + + auto avg_fill_time = sum_fill_time / repeat_outer; auto avg_cycle_time = sum_cycle_time / repeat_outer; - auto avg_both_time = sum_both_time / repeat_outer; + auto avg_both_time = sum_both_time / repeat_outer; - printf( "\"mempool: fill time (min, avg)\" %.8f %.8f\n" - , min_fill_time - , avg_fill_time ); + printf("\"mempool: fill time (min, avg)\" %.8f %.8f\n", min_fill_time, + avg_fill_time); - printf( "\"mempool: cycle time (min, avg)\" %.8f %.8f\n" - , min_cycle_time - , avg_cycle_time ); + printf("\"mempool: cycle time (min, avg)\" %.8f %.8f\n", min_cycle_time, + avg_cycle_time); - printf( "\"mempool: test time (min, avg)\" %.8f %.8f\n" - , min_both_time - , avg_both_time ); + printf("\"mempool: test time (min, avg)\" %.8f %.8f\n", min_both_time, + avg_both_time); - printf( "\"mempool: fill ops per second (max, avg)\" %g %g\n" - , number_alloc / min_fill_time - , number_alloc / avg_fill_time ); + printf("\"mempool: fill ops per second (max, avg)\" %g %g\n", + number_alloc / min_fill_time, number_alloc / avg_fill_time); - printf( "\"mempool: cycle ops per second (max, avg)\" %g %g\n" - , (2 * number_alloc * repeat_inner) / min_cycle_time - , (2 * number_alloc * repeat_inner) / avg_cycle_time ); + printf("\"mempool: cycle ops per second (max, avg)\" %g %g\n", + (2 * number_alloc * repeat_inner) / min_cycle_time, + (2 * number_alloc * repeat_inner) / avg_cycle_time); } - diff --git a/lib/kokkos/core/perf_test/test_taskdag.cpp b/lib/kokkos/core/perf_test/test_taskdag.cpp index 41198edfe1..a97edc59e8 100644 --- a/lib/kokkos/core/perf_test/test_taskdag.cpp +++ b/lib/kokkos/core/perf_test/test_taskdag.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -43,13 +44,10 @@ #include -#if ! defined( KOKKOS_ENABLE_TASKDAG ) || \ - defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) +#if !defined(KOKKOS_ENABLE_TASKDAG) || \ + defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) -int main() -{ - return 0 ; -} +int main() { return 0; } #else @@ -60,187 +58,160 @@ int main() #include -using ExecSpace = Kokkos::DefaultExecutionSpace ; +using ExecSpace = Kokkos::DefaultExecutionSpace; -inline -long eval_fib( long n ) -{ +inline long eval_fib(long n) { constexpr long mask = 0x03; - long fib[4] = { 0, 1, 0, 0 }; + long fib[4] = {0, 1, 0, 0}; - for ( long i = 2; i <= n; ++i ) { - fib[ i & mask ] = fib[ ( i - 1 ) & mask ] + fib[ ( i - 2 ) & mask ]; + for (long i = 2; i <= n; ++i) { + fib[i & mask] = fib[(i - 1) & mask] + fib[(i - 2) & mask]; } - return fib[ n & mask ]; + return fib[n & mask]; } -inline -long fib_alloc_count( long n ) -{ +inline long fib_alloc_count(long n) { constexpr long mask = 0x03; - long count[4] = { 1, 1, 0, 0 }; + long count[4] = {1, 1, 0, 0}; - for ( long i = 2; i <= n; ++i ) { - count[ i & mask ] = 2 // this task plus the 'when_all' task - + count[ ( i - 1 ) & mask ] - + count[ ( i - 2 ) & mask ]; + for (long i = 2; i <= n; ++i) { + count[i & mask] = 2 // this task plus the 'when_all' task + + count[(i - 1) & mask] + count[(i - 2) & mask]; } - return count[ n & mask ]; + return count[n & mask]; } -template< class Scheduler > +template struct TestFib { + using MemorySpace = typename Scheduler::memory_space; + using MemberType = typename Scheduler::member_type; + using FutureType = Kokkos::BasicFuture; - using MemorySpace = typename Scheduler::memory_space ; - using MemberType = typename Scheduler::member_type ; - using FutureType = Kokkos::BasicFuture< long , Scheduler > ; - - typedef long value_type ; + typedef long value_type; - FutureType dep[2] ; - const value_type n ; + FutureType dep[2]; + const value_type n; KOKKOS_INLINE_FUNCTION - TestFib( const value_type arg_n ) - : dep{} , n( arg_n ) {} + TestFib(const value_type arg_n) : dep{}, n(arg_n) {} KOKKOS_INLINE_FUNCTION - void operator()( MemberType & member, value_type & result ) noexcept - { - auto& sched = member.scheduler(); - if ( n < 2 ) { - result = n ; - } - else if ( ! dep[0].is_null() && ! dep[1].is_null() ) { - result = dep[0].get() + dep[1].get(); - } - else { - // Spawn new children and respawn myself to sum their results. - // Spawn lower value at higher priority as it has a shorter - // path to completion. - - dep[1] = Kokkos::task_spawn - ( Kokkos::TaskSingle( sched, Kokkos::TaskPriority::High ) - , TestFib( n - 2 ) ); - - dep[0] = Kokkos::task_spawn - ( Kokkos::TaskSingle( sched ) - , TestFib( n - 1 ) ); - - auto fib_all = sched.when_all( dep, 2 ); - - if ( ! dep[0].is_null() && ! dep[1].is_null() && ! fib_all.is_null() ) { - // High priority to retire this branch. - Kokkos::respawn( this, fib_all, Kokkos::TaskPriority::High ); - } - else { - Kokkos::abort("Failed nested task spawn (allocation)"); - } + void operator()(MemberType& member, value_type& result) noexcept { + auto& sched = member.scheduler(); + if (n < 2) { + result = n; + } else if (!dep[0].is_null() && !dep[1].is_null()) { + result = dep[0].get() + dep[1].get(); + } else { + // Spawn new children and respawn myself to sum their results. + // Spawn lower value at higher priority as it has a shorter + // path to completion. + + dep[1] = Kokkos::task_spawn( + Kokkos::TaskSingle(sched, Kokkos::TaskPriority::High), + TestFib(n - 2)); + + dep[0] = Kokkos::task_spawn(Kokkos::TaskSingle(sched), TestFib(n - 1)); + + auto fib_all = sched.when_all(dep, 2); + + if (!dep[0].is_null() && !dep[1].is_null() && !fib_all.is_null()) { + // High priority to retire this branch. + Kokkos::respawn(this, fib_all, Kokkos::TaskPriority::High); + } else { + Kokkos::abort("Failed nested task spawn (allocation)"); } } + } }; +int main(int argc, char* argv[]) { + static const char help[] = "--help"; + static const char alloc_size[] = "--alloc_size="; + static const char super_size[] = "--super_size="; + static const char repeat_outer[] = "--repeat_outer="; + static const char input_value[] = "--input="; + long total_alloc_size = 1000000; + int min_superblock_size = 10000; + int test_repeat_outer = 1; + int fib_input = 4; -int main( int argc , char* argv[] ) -{ - static const char help[] = "--help" ; - static const char alloc_size[] = "--alloc_size=" ; - static const char super_size[] = "--super_size=" ; - static const char repeat_outer[] = "--repeat_outer=" ; - static const char input_value[] = "--input=" ; + int ask_help = 0; - long total_alloc_size = 1000000 ; - int min_superblock_size = 10000 ; - int test_repeat_outer = 1 ; - int fib_input = 4 ; + for (int i = 1; i < argc; i++) { + const char* const a = argv[i]; - int ask_help = 0 ; + if (!strncmp(a, help, strlen(help))) ask_help = 1; - for(int i=1;i; - typedef TestFib< Scheduler > Functor ; + typedef TestFib Functor; - Kokkos::initialize(argc,argv); + Kokkos::initialize(argc, argv); { - - Scheduler sched( Functor::MemorySpace() - , total_alloc_size - , min_block_size - , max_block_size - , min_superblock_size - ); + Scheduler sched(Functor::MemorySpace(), total_alloc_size, min_block_size, + max_block_size, min_superblock_size); Functor::FutureType f = - Kokkos::host_spawn( Kokkos::TaskSingle( sched ) - , Functor( fib_input ) - ); + Kokkos::host_spawn(Kokkos::TaskSingle(sched), Functor(fib_input)); - Kokkos::wait( sched ); + Kokkos::wait(sched); test_result = f.get(); - //task_count_max = sched.allocated_task_count_max(); - //task_count_accum = sched.allocated_task_count_accum(); + // task_count_max = sched.allocated_task_count_max(); + // task_count_accum = sched.allocated_task_count_accum(); - //if ( number_alloc != task_count_accum ) { + // if ( number_alloc != task_count_accum ) { // std::cout << " number_alloc( " << number_alloc << " )" // << " != task_count_accum( " << task_count_accum << " )" // << std::endl ; //} - if ( fib_output != test_result ) { + if (fib_output != test_result) { std::cout << " answer( " << fib_output << " )" - << " != result( " << test_result << " )" - << std::endl ; + << " != result( " << test_result << " )" << std::endl; } - if ( fib_output != test_result) { // || number_alloc != task_count_accum ) { + if (fib_output != test_result) { // || number_alloc != task_count_accum ) { printf(" TEST FAILED\n"); return -1; } @@ -248,41 +219,34 @@ int main( int argc , char* argv[] ) double min_time = std::numeric_limits::max(); double time_sum = 0; - for ( int i = 0 ; i < test_repeat_outer ; ++i ) { - Kokkos::Impl::Timer timer ; + for (int i = 0; i < test_repeat_outer; ++i) { + Kokkos::Impl::Timer timer; Functor::FutureType ftmp = - Kokkos::host_spawn( Kokkos::TaskSingle( sched ) - , Functor( fib_input ) - ); + Kokkos::host_spawn(Kokkos::TaskSingle(sched), Functor(fib_input)); - Kokkos::wait( sched ); + Kokkos::wait(sched); auto this_time = timer.seconds(); - min_time = std::min(min_time, this_time); + min_time = std::min(min_time, this_time); time_sum += this_time; } auto avg_time = time_sum / test_repeat_outer; - printf( "\"taskdag: alloc super repeat input output task-accum task-max\" %ld %d %d %d %ld %ld %ld\n" - , total_alloc_size - , min_superblock_size - , test_repeat_outer - , fib_input - , fib_output - , task_count_accum - , task_count_max ); - - printf( "\"taskdag: time (min, avg)\" %g %g\n", min_time, avg_time); - printf( "\"taskdag: tasks per second (max, avg)\" %g %g\n" - , number_alloc / min_time - , number_alloc / avg_time ); - } // end scope to destroy scheduler prior to finalize + printf( + "\"taskdag: alloc super repeat input output task-accum task-max\" %ld " + "%d %d %d %ld %ld %ld\n", + total_alloc_size, min_superblock_size, test_repeat_outer, fib_input, + fib_output, task_count_accum, task_count_max); + + printf("\"taskdag: time (min, avg)\" %g %g\n", min_time, avg_time); + printf("\"taskdag: tasks per second (max, avg)\" %g %g\n", + number_alloc / min_time, number_alloc / avg_time); + } // end scope to destroy scheduler prior to finalize Kokkos::finalize(); - return 0 ; + return 0; } #endif - diff --git a/lib/kokkos/core/src/CMakeLists.txt b/lib/kokkos/core/src/CMakeLists.txt index a941c5da0c..eb058a982e 100644 --- a/lib/kokkos/core/src/CMakeLists.txt +++ b/lib/kokkos/core/src/CMakeLists.txt @@ -1,124 +1,81 @@ - - -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}) - -#----------------------------------------------------------------------------- - -SET(TRILINOS_INCDIR ${CMAKE_INSTALL_PREFIX}/${${PROJECT_NAME}_INSTALL_INCLUDE_DIR}) - -#----------------------------------------------------------------------------- - -IF(KOKKOS_LEGACY_TRIBITS) - - MESSAGE("LEGACY STUFF GETTING CALLED") - - IF(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION) - MESSAGE("GOING INTO ETI DIR") - ADD_SUBDIRECTORY(eti) - INCLUDE_DIRECTORIES("${CMAKE_CURRENT_SOURCE_DIR}/eti") - ENDIF() - - ASSERT_DEFINED(${PROJECT_NAME}_ENABLE_CXX11) - ASSERT_DEFINED(${PACKAGE_NAME}_ENABLE_CUDA) - - SET(HEADERS_PUBLIC "") - SET(HEADERS_PRIVATE "") - SET(SOURCES "") - - FILE(GLOB HEADERS_PUBLIC Kokkos*.hpp) - LIST( APPEND HEADERS_PUBLIC ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}_config.h ) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_IMPL impl/*.hpp) - FILE(GLOB SOURCES_IMPL impl/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_IMPL} ) - LIST(APPEND SOURCES ${SOURCES_IMPL} ) - - INSTALL(FILES ${HEADERS_IMPL} DESTINATION ${TRILINOS_INCDIR}/impl/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_THREADS Threads/*.hpp) - FILE(GLOB SOURCES_THREADS Threads/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_THREADS} ) - LIST(APPEND SOURCES ${SOURCES_THREADS} ) - - INSTALL(FILES ${HEADERS_THREADS} DESTINATION ${TRILINOS_INCDIR}/Threads/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_OPENMP OpenMP/*.hpp) - FILE(GLOB SOURCES_OPENMP OpenMP/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_OPENMP} ) - LIST(APPEND SOURCES ${SOURCES_OPENMP} ) - - INSTALL(FILES ${HEADERS_OPENMP} DESTINATION ${TRILINOS_INCDIR}/OpenMP/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_HPX HPX/*.hpp) - FILE(GLOB SOURCES_HPX HPX/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_HPX} ) - LIST(APPEND SOURCES ${SOURCES_HPX} ) - - INSTALL(FILES ${HEADERS_HPX} DESTINATION ${TRILINOS_INCDIR}/HPX/) - - #----------------------------------------------------------------------------- - - FILE(GLOB HEADERS_CUDA Cuda/*.hpp) - FILE(GLOB SOURCES_CUDA Cuda/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_CUDA} ) - LIST(APPEND SOURCES ${SOURCES_CUDA} ) - - INSTALL(FILES ${HEADERS_CUDA} DESTINATION ${TRILINOS_INCDIR}/Cuda/) - - #----------------------------------------------------------------------------- - FILE(GLOB HEADERS_QTHREADS Qthreads/*.hpp) - FILE(GLOB SOURCES_QTHREADS Qthreads/*.cpp) - - LIST(APPEND HEADERS_PRIVATE ${HEADERS_QTHREADS} ) - LIST(APPEND SOURCES ${SOURCES_QTHREADS} ) - - IF(KOKKOS_ENABLE_EXPLICIT_INSTANTIATION) - LIST(APPEND SOURCES ${ETI_SOURCES} ) - ENDIF() - - INSTALL(FILES ${HEADERS_QTHREADS} DESTINATION ${TRILINOS_INCDIR}/Qthreads/) - - TRIBITS_ADD_LIBRARY( - kokkoscore - HEADERS ${HEADERS_PUBLIC} - NOINSTALLHEADERS ${HEADERS_PRIVATE} - SOURCES ${SOURCES} - DEPLIBS - ) - -#----------------------------------------------------------------------------- -# In the new build system, sources are calculated by Makefile.kokkos -else() - - INSTALL (DIRECTORY - "${CMAKE_CURRENT_SOURCE_DIR}/" - DESTINATION ${TRILINOS_INCDIR} - FILES_MATCHING PATTERN "*.hpp" - ) - - TRIBITS_ADD_LIBRARY( - kokkoscore - SOURCES ${KOKKOS_CORE_SRCS} - DEPLIBS - ) - -endif() -#----------------------------------------------------------------------------- - -# build and install pkgconfig file -CONFIGURE_FILE(kokkos.pc.in kokkos.pc @ONLY) -INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/kokkos.pc DESTINATION lib/pkgconfig) +#I have to leave these here for tribits +KOKKOS_INCLUDE_DIRECTORIES( + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} + ${KOKKOS_TOP_BUILD_DIR} +) + +INSTALL (DIRECTORY + "${CMAKE_CURRENT_SOURCE_DIR}/" + DESTINATION ${KOKKOS_HEADER_DIR} + FILES_MATCHING PATTERN "*.hpp" +) + +SET(KOKKOS_CORE_SRCS) +APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/*.cpp) + +IF (KOKKOS_ENABLE_ROCM) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ROCm/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/ROCm/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_CUDA) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Cuda/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRC ${CMAKE_CURRENT_SOURCE_DIR/eti/Cuda/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_OPENMP) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/OpenMP/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/OpenMP/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_PTHREAD) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/Threads/*.cpp) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/Threads/*.cpp) + ENDIF() +ENDIF() + +IF (KOKKOS_ENABLE_HPX) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/HPX/*.cpp) +ENDIF() + +IF (NOT KOKKOS_ENABLE_MEMKIND) + LIST(REMOVE_ITEM KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/Kokkos_HBWSpace.cpp) +ENDIF() + +IF (KOKKOS_ENABLE_SERIAL) + IF (KOKKOS_ENABLE_ETI) + APPEND_GLOB(KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/eti/Serial/*.cpp) + ENDIF() +ELSE() + LIST(REMOVE_ITEM KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/Kokkos_Serial.cpp) + LIST(REMOVE_ITEM KOKKOS_CORE_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/impl/Kokkos_Serial_task.cpp) +ENDIF() + +KOKKOS_ADD_LIBRARY( + kokkoscore + SOURCES ${KOKKOS_CORE_SRCS} +) + +SET_TARGET_PROPERTIES(kokkoscore PROPERTIES VERSION ${Kokkos_VERSION}) + +KOKKOS_LIB_INCLUDE_DIRECTORIES(kokkoscore + ${KOKKOS_TOP_BUILD_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_CURRENT_SOURCE_DIR} +) + +KOKKOS_LINK_TPL(kokkoscore PUBLIC HWLOC) +KOKKOS_LINK_TPL(kokkoscore PUBLIC MEMKIND) +KOKKOS_LINK_TPL(kokkoscore PUBLIC CUDA) +KOKKOS_LINK_TPL(kokkoscore PUBLIC HPX) +KOKKOS_LINK_TPL(kokkoscore PUBLIC LIBDL) +KOKKOS_LINK_TPL(kokkoscore PUBLIC LIBRT) +KOKKOS_LINK_TPL(kokkoscore PUBLIC PTHREAD) diff --git a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp index 8a83dfff4a..3706263921 100644 --- a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp +++ b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_EXP_ITERATE_TILE_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -55,181 +56,182 @@ //#include // Including the file above, leads to following type of errors: -// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete type is not allowed -// As a result, recreate cuda_parallel_launch and associated code +// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete +// type is not allowed As a result, recreate cuda_parallel_launch and associated +// code #if defined(KOKKOS_ENABLE_PROFILING) #include #include #endif -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { // ------------------------------------------------------------------ // -template< class DriverType > -__global__ -static void cuda_parallel_launch( const DriverType driver ) -{ +template +__global__ static void cuda_parallel_launch(const DriverType driver) { driver(); } -template< class DriverType > -struct CudaLaunch -{ - inline - CudaLaunch( const DriverType & driver - , const dim3 & grid - , const dim3 & block - ) - { - cuda_parallel_launch< DriverType ><<< grid , block >>>(driver); +template +struct CudaLaunch { + inline CudaLaunch(const DriverType& driver, const dim3& grid, + const dim3& block) { + cuda_parallel_launch<<>>(driver); } - }; // ------------------------------------------------------------------ // -template< int N , typename RP , typename Functor , typename Tag > +template struct apply_impl; -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<2,RP,Functor,void > -{ +template +struct apply_impl<2, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} - - inline __device__ - void exec_range() const - { -// LL - if (RP::inner_direction == RP::Left) { - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1); + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} + + inline __device__ void exec_range() const { + // LL + if (RP::inner_direction == RP::Left) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1); + } } } } } - } -// LR - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - m_func(offset_0 , offset_1); + // LR + else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + m_func(offset_0, offset_1); + } } } } } - } - - } //end exec_range -private: - const RP & m_rp; - const Functor & m_func; + } // end exec_range + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<2,RP,Functor,Tag> -{ +template +struct apply_impl<2, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} - - inline __device__ - void exec_range() const - { - if (RP::inner_direction == RP::Left) { - // Loop over size maxnumblocks until full range covered - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1); + inline __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} + + inline __device__ void exec_range() const { + if (RP::inner_direction == RP::Left) { + // Loop over size maxnumblocks until full range covered + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1); + } } } } - } - } - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - m_func(Tag(), offset_0 , offset_1); + } else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + m_func(Tag(), offset_0, offset_1); + } } } } } - } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<3,RP,Functor,void > -{ +template +struct apply_impl<3, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2); } } } @@ -237,83 +239,100 @@ struct apply_impl<3,RP,Functor,void > } } } -// LR - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - m_func(offset_0 , offset_1 , offset_2); + // LR + else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.z < m_rp.m_tile[2]) { + m_func(offset_0, offset_1, offset_2); + } } } } } } } - } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<3,RP,Functor,Tag> -{ +template +struct apply_impl<3, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } } } } - } - else { - for ( index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.z < m_rp.m_tile[2] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + } else { + for (index_type tile_id0 = blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; + tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; + tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.z < m_rp.m_tile[2]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } @@ -322,61 +341,64 @@ struct apply_impl<3,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<4,RP,Functor,void > -{ +template +struct apply_impl<4, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; + tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -386,35 +408,44 @@ struct apply_impl<4,RP,Functor,void > } } } -// LR + // LR else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + threadIdx.z < m_rp.m_tile[3]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -425,58 +456,62 @@ struct apply_impl<4,RP,Functor,void > } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<4,RP,Functor,Tag> -{ +template +struct apply_impl<4, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; + tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; + tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -485,35 +520,43 @@ struct apply_impl<4,RP,Functor,Tag> } } } - } - else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + } else { + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && threadIdx.z < m_rp.m_tile[3] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + threadIdx.z < m_rp.m_tile[3]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -524,77 +567,83 @@ struct apply_impl<4,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<5,RP,Functor,void > -{ +template +struct apply_impl<5, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -606,50 +655,63 @@ struct apply_impl<5,RP,Functor,void > } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + threadIdx.z < m_rp.m_tile[4]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -662,74 +724,82 @@ struct apply_impl<5,RP,Functor,void > } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<5,RP,Functor,Tag> -{ +template +struct apply_impl<5, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -741,50 +811,63 @@ struct apply_impl<5,RP,Functor,Tag> } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && threadIdx.z < m_rp.m_tile[4] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + threadIdx.z < m_rp.m_tile[4]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -797,91 +880,101 @@ struct apply_impl<5,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor > -struct apply_impl<6,RP,Functor,void > -{ +template +struct apply_impl<6, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = blockIdx.z % numbl4; const index_type tile_id5 = blockIdx.z / numbl4; - const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -895,65 +988,82 @@ struct apply_impl<6,RP,Functor,void > } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = blockIdx.z / numbl5; const index_type tile_id5 = blockIdx.z % numbl5; - const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -968,89 +1078,100 @@ struct apply_impl<6,RP,Functor,void > } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct apply_impl<6,RP,Functor,Tag> -{ +template +struct apply_impl<6, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - apply_impl( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ apply_impl(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - inline __device__ - void exec_range() const - { -// LL + inline __device__ void exec_range() const { + // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = blockIdx.x % numbl0; const index_type tile_id1 = blockIdx.x / numbl0; - const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = blockIdx.y % numbl2; const index_type tile_id3 = blockIdx.y / numbl2; - const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = blockIdx.z % numbl4; const index_type tile_id5 = blockIdx.z / numbl4; - const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1064,65 +1185,82 @@ struct apply_impl<6,RP,Functor,Tag> } } } -// LR + // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = blockIdx.x / numbl1; const index_type tile_id1 = blockIdx.x % numbl1; - const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = blockIdx.y / numbl3; const index_type tile_id3 = blockIdx.y % numbl3; - const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = blockIdx.z / numbl5; const index_type tile_id5 = blockIdx.z % numbl5; - const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1137,127 +1275,118 @@ struct apply_impl<6,RP,Functor,Tag> } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // ---------------------------------------------------------------------------------- -template < typename RP - , typename Functor - , typename Tag - > -struct DeviceIterateTile -{ - using index_type = typename RP::index_type; +template +struct DeviceIterateTile { + using index_type = typename RP::index_type; using array_index_type = typename RP::array_index_type; - using point_type = typename RP::point_type; + using point_type = typename RP::point_type; struct VoidDummy {}; - typedef typename std::conditional< std::is_same::value, VoidDummy, Tag>::type usable_tag; - - DeviceIterateTile( const RP & rp, const Functor & func ) - : m_rp{rp} - , m_func{func} - {} - -private: - inline __device__ - void apply() const - { - apply_impl(m_rp,m_func).exec_range(); - } //end apply - -public: - - inline - __device__ - void operator()(void) const - { - this-> apply(); - } + typedef typename std::conditional::value, VoidDummy, + Tag>::type usable_tag; + + DeviceIterateTile(const RP& rp, const Functor& func) + : m_rp{rp}, m_func{func} {} + + private: + inline __device__ void apply() const { + apply_impl(m_rp, m_func).exec_range(); + } // end apply + + public: + inline __device__ void operator()(void) const { this->apply(); } - inline - void execute() const - { - const array_index_type maxblocks = 65535; //not true for blockIdx.x for newer archs - if ( RP::rank == 2 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , 1); + inline void execute() const { + const array_index_type maxblocks = + 65535; // not true for blockIdx.x for newer archs + if (RP::rank == 2) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], 1); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , 1 - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 3 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , m_rp.m_tile[2] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + 1); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 3) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], m_rp.m_tile[2]); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 4 ) - { - // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2] , m_rp.m_tile[3] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1) / block.z, + maxblocks)); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 4) { + // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], m_rp.m_tile[2], + m_rp.m_tile[3]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 5 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1) / block.z, + maxblocks)); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 5) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], m_rp.m_tile[4]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else if ( RP::rank == 6 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4]*m_rp.m_tile[5] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1) / block.z, + maxblocks)); + CudaLaunch(*this, grid, block); + } else if (RP::rank == 6) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], + m_rp.m_tile[4] * m_rp.m_tile[5]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[4] * m_rp.m_tile_end[5] ) - , static_cast(maxblocks) ) - ); - CudaLaunch< DeviceIterateTile >( *this , grid , block ); - } - else - { + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[4] * m_rp.m_tile_end[5]), + static_cast(maxblocks))); + CudaLaunch(*this, grid, block); + } else { printf("Kokkos::MDRange Error: Exceeded rank bounds with Cuda\n"); Kokkos::abort("Aborting"); } - } //end execute + } // end execute -protected: - const RP m_rp; - const Functor m_func; + protected: + const RP m_rp; + const Functor m_func; }; -} } //end namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos #endif #endif - diff --git a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp index 636e05c8ac..cb7f5971ae 100644 --- a/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp +++ b/lib/kokkos/core/src/Cuda/KokkosExp_Cuda_IterateTile_Refactor.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_EXP_ITERATE_TILE_REFACTOR_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -55,49 +56,52 @@ // #include // Including the file above leads to following type of errors: -// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete type is not allowed -// use existing Kokkos functionality, e.g. max blocks, once resolved +// /home/ndellin/kokkos/core/src/Cuda/Kokkos_CudaExec.hpp(84): error: incomplete +// type is not allowed use existing Kokkos functionality, e.g. max blocks, once +// resolved #if defined(KOKKOS_ENABLE_PROFILING) #include #include #endif -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { namespace Refactor { // ------------------------------------------------------------------ // // ParallelFor iteration pattern -template< int N , typename RP , typename Functor , typename Tag > +template struct DeviceIterateTile; -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<2,RP,Functor,void > -{ +template +struct DeviceIterateTile<2, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { // LL if (RP::inner_direction == RP::Left) { - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1); + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1); } } } @@ -105,108 +109,125 @@ struct DeviceIterateTile<2,RP,Functor,void > } // LR else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - m_func(offset_0 , offset_1); + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + m_func(offset_0, offset_1); } } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<2,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<2, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { // Loop over size maxnumblocks until full range covered - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1); + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1); } } } } - } - else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - m_func(Tag(), offset_0 , offset_1); + } else { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + m_func(Tag(), offset_0, offset_1); } } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<3,RP,Functor,void > -{ +template +struct DeviceIterateTile<3, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { // LL if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2); } } } @@ -216,18 +237,28 @@ struct DeviceIterateTile<3,RP,Functor,void > } // LR else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - m_func(offset_0 , offset_1 , offset_2); + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + m_func(offset_0, offset_1, offset_2); } } } @@ -235,61 +266,74 @@ struct DeviceIterateTile<3,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<3,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<3, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} - inline __device__ - void exec_range() const - { + inline __device__ void exec_range() const { if (RP::inner_direction == RP::Left) { - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } } } } - } - else { - for ( index_type tile_id0 = (index_type)blockIdx.x; tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x ) { - const index_type offset_0 = tile_id0*m_rp.m_tile[0] + (index_type)threadIdx.x + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && (index_type)threadIdx.x < m_rp.m_tile[0] ) { - - for ( index_type tile_id1 = (index_type)blockIdx.y; tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && (index_type)threadIdx.y < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.z; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.z < m_rp.m_tile[2] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2); + } else { + for (index_type tile_id0 = (index_type)blockIdx.x; + tile_id0 < m_rp.m_tile_end[0]; tile_id0 += gridDim.x) { + const index_type offset_0 = tile_id0 * m_rp.m_tile[0] + + (index_type)threadIdx.x + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + (index_type)threadIdx.x < m_rp.m_tile[0]) { + for (index_type tile_id1 = (index_type)blockIdx.y; + tile_id1 < m_rp.m_tile_end[1]; tile_id1 += gridDim.y) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + (index_type)threadIdx.y < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.z; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.z) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.z < m_rp.m_tile[2]) { + m_func(Tag(), offset_0, offset_1, offset_2); } } } @@ -297,64 +341,72 @@ struct DeviceIterateTile<3,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<4,RP,Functor,void > -{ +template +struct DeviceIterateTile<4, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -366,33 +418,42 @@ struct DeviceIterateTile<4,RP,Functor,void > } // LR else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + m_func(offset_0, offset_1, offset_2, offset_3); } } } @@ -402,61 +463,70 @@ struct DeviceIterateTile<4,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for void tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<4,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<4, RP, Functor, Tag> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); if (RP::inner_direction == RP::Left) { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag(), offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -465,35 +535,43 @@ struct DeviceIterateTile<4,RP,Functor,Tag> } } } - } - else { - const index_type temp0 = m_rp.m_tile_end[0]; - const index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + } else { + const index_type temp0 = m_rp.m_tile_end[0]; + const index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = tile_id1*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type tile_id2 = (index_type)blockIdx.y; tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y ) { - const index_type offset_2 = tile_id2*m_rp.m_tile[2] + (index_type)threadIdx.y + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && (index_type)threadIdx.y < m_rp.m_tile[2] ) { - - for ( index_type tile_id3 = (index_type)blockIdx.z; tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z ) { - const index_type offset_3 = tile_id3*m_rp.m_tile[3] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && (index_type)threadIdx.z < m_rp.m_tile[3] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3); + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = tile_id1 * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type tile_id2 = (index_type)blockIdx.y; + tile_id2 < m_rp.m_tile_end[2]; tile_id2 += gridDim.y) { + const index_type offset_2 = tile_id2 * m_rp.m_tile[2] + + (index_type)threadIdx.y + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + (index_type)threadIdx.y < m_rp.m_tile[2]) { + for (index_type tile_id3 = (index_type)blockIdx.z; + tile_id3 < m_rp.m_tile_end[3]; tile_id3 += gridDim.z) { + const index_type offset_3 = tile_id3 * m_rp.m_tile[3] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + (index_type)threadIdx.z < m_rp.m_tile[3]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3); } } } @@ -503,80 +581,90 @@ struct DeviceIterateTile<4,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<5,RP,Functor,void > -{ +template +struct DeviceIterateTile<5, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -590,48 +678,61 @@ struct DeviceIterateTile<5,RP,Functor,void > } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -643,77 +744,89 @@ struct DeviceIterateTile<5,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<5,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<5, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4); + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = i * m_rp.m_tile[0] + + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -727,48 +840,61 @@ struct DeviceIterateTile<5,RP,Functor,Tag> } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type tile_id4 = (index_type)blockIdx.z; tile_id4 < m_rp.m_tile_end[4]; tile_id4 += gridDim.z ) { - const index_type offset_4 = tile_id4*m_rp.m_tile[4] + (index_type)threadIdx.z + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && (index_type)threadIdx.z < m_rp.m_tile[4] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4); + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type tile_id4 = (index_type)blockIdx.z; + tile_id4 < m_rp.m_tile_end[4]; + tile_id4 += gridDim.z) { + const index_type offset_4 = tile_id4 * m_rp.m_tile[4] + + (index_type)threadIdx.z + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + (index_type)threadIdx.z < m_rp.m_tile[4]) { + m_func(Tag(), offset_0, offset_1, offset_2, offset_3, + offset_4); } } } @@ -780,94 +906,107 @@ struct DeviceIterateTile<5,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor > -struct DeviceIterateTile<6,RP,Functor,void > -{ +template +struct DeviceIterateTile<6, RP, Functor, void> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z % numbl4; const index_type tile_id5 = (index_type)blockIdx.z / numbl4; - const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -883,63 +1022,80 @@ struct DeviceIterateTile<6,RP,Functor,void > } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z / numbl5; const index_type tile_id5 = (index_type)blockIdx.z % numbl5; - const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(offset_0, offset_1, offset_2, offset_3, + offset_4, offset_5); } } } @@ -953,92 +1109,106 @@ struct DeviceIterateTile<6,RP,Functor,void > } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; // Specializations for tag type -template< typename RP , typename Functor , typename Tag > -struct DeviceIterateTile<6,RP,Functor,Tag> -{ +template +struct DeviceIterateTile<6, RP, Functor, Tag> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ ) - : m_rp(rp_) - , m_func(f_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_) + : m_rp(rp_), m_func(f_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); // LL if (RP::inner_direction == RP::Left) { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl0 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl1 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl0 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl0 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl1 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl0) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x % numbl0; const index_type tile_id1 = (index_type)blockIdx.x / numbl0; - const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; - const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; + const index_type thr_id0 = (index_type)threadIdx.x % m_rp.m_tile[0]; + const index_type thr_id1 = (index_type)threadIdx.x / m_rp.m_tile[0]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl2 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl3 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl2 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl2 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl3 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl2) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y % numbl2; const index_type tile_id3 = (index_type)blockIdx.y / numbl2; - const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; - const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; + const index_type thr_id2 = (index_type)threadIdx.y % m_rp.m_tile[2]; + const index_type thr_id3 = (index_type)threadIdx.y / m_rp.m_tile[2]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl4 = ( temp0 <= max_blocks ? temp0 : max_blocks ) ; - const index_type numbl5 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl4 ) : - ( temp1 <= max_blocks ? temp1 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl4 = (temp0 <= max_blocks ? temp0 : max_blocks); + const index_type numbl5 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl4) + : (temp1 <= max_blocks ? temp1 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z % numbl4; const index_type tile_id5 = (index_type)blockIdx.z / numbl4; - const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; - const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type j = tile_id1 ; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type i = tile_id0 ; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3, offset_4, offset_5); + const index_type thr_id4 = (index_type)threadIdx.z % m_rp.m_tile[4]; + const index_type thr_id5 = (index_type)threadIdx.z / m_rp.m_tile[4]; + + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4) { + const index_type offset_4 = + m * m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = + l * m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = k * m_rp.m_tile[2] + thr_id2 + + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && + thr_id2 < m_rp.m_tile[2]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; + j += numbl1) { + const index_type offset_1 = j * m_rp.m_tile[1] + + thr_id1 + + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && + thr_id1 < m_rp.m_tile[1]) { + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; + i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && + thr_id0 < m_rp.m_tile[0]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1054,63 +1224,80 @@ struct DeviceIterateTile<6,RP,Functor,Tag> } // LR else { - index_type temp0 = m_rp.m_tile_end[0]; - index_type temp1 = m_rp.m_tile_end[1]; - const index_type numbl1 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl0 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl1 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + index_type temp0 = m_rp.m_tile_end[0]; + index_type temp1 = m_rp.m_tile_end[1]; + const index_type numbl1 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl0 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl1) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id0 = (index_type)blockIdx.x / numbl1; const index_type tile_id1 = (index_type)blockIdx.x % numbl1; - const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; - const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; + const index_type thr_id0 = (index_type)threadIdx.x / m_rp.m_tile[1]; + const index_type thr_id1 = (index_type)threadIdx.x % m_rp.m_tile[1]; - temp0 = m_rp.m_tile_end[2]; - temp1 = m_rp.m_tile_end[3]; - const index_type numbl3 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl2 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl3 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[2]; + temp1 = m_rp.m_tile_end[3]; + const index_type numbl3 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl2 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl3) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id2 = (index_type)blockIdx.y / numbl3; const index_type tile_id3 = (index_type)blockIdx.y % numbl3; - const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; - const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; + const index_type thr_id2 = (index_type)threadIdx.y / m_rp.m_tile[3]; + const index_type thr_id3 = (index_type)threadIdx.y % m_rp.m_tile[3]; - temp0 = m_rp.m_tile_end[4]; - temp1 = m_rp.m_tile_end[5]; - const index_type numbl5 = ( temp1 <= max_blocks ? temp1 : max_blocks ) ; - const index_type numbl4 = ( temp0*temp1 > max_blocks ? index_type( max_blocks / numbl5 ) : - ( temp0 <= max_blocks ? temp0 : max_blocks ) ); + temp0 = m_rp.m_tile_end[4]; + temp1 = m_rp.m_tile_end[5]; + const index_type numbl5 = (temp1 <= max_blocks ? temp1 : max_blocks); + const index_type numbl4 = + (temp0 * temp1 > max_blocks + ? index_type(max_blocks / numbl5) + : (temp0 <= max_blocks ? temp0 : max_blocks)); const index_type tile_id4 = (index_type)blockIdx.z / numbl5; const index_type tile_id5 = (index_type)blockIdx.z % numbl5; - const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; - const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; - - for ( index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0 ) { - const index_type offset_0 = i*m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; - if ( offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0] ) { - - for ( index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1 ) { - const index_type offset_1 = j*m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; - if ( offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1] ) { - - for ( index_type k = tile_id2; k < m_rp.m_tile_end[2]; k += numbl2 ) { - const index_type offset_2 = k*m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; - if ( offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2] ) { - - for ( index_type l = tile_id3; l < m_rp.m_tile_end[3]; l += numbl3 ) { - const index_type offset_3 = l*m_rp.m_tile[3] + thr_id3 + (index_type)m_rp.m_lower[3]; - if ( offset_3 < m_rp.m_upper[3] && thr_id3 < m_rp.m_tile[3] ) { - - for ( index_type m = tile_id4; m < m_rp.m_tile_end[4]; m += numbl4 ) { - const index_type offset_4 = m*m_rp.m_tile[4] + thr_id4 + (index_type)m_rp.m_lower[4]; - if ( offset_4 < m_rp.m_upper[4] && thr_id4 < m_rp.m_tile[4] ) { - - for ( index_type n = tile_id5; n < m_rp.m_tile_end[5]; n += numbl5 ) { - const index_type offset_5 = n*m_rp.m_tile[5] + thr_id5 + (index_type)m_rp.m_lower[5]; - if ( offset_5 < m_rp.m_upper[5] && thr_id5 < m_rp.m_tile[5] ) { - m_func(Tag() , offset_0 , offset_1 , offset_2 , offset_3 , offset_4 , offset_5); + const index_type thr_id4 = (index_type)threadIdx.z / m_rp.m_tile[5]; + const index_type thr_id5 = (index_type)threadIdx.z % m_rp.m_tile[5]; + + for (index_type i = tile_id0; i < m_rp.m_tile_end[0]; i += numbl0) { + const index_type offset_0 = + i * m_rp.m_tile[0] + thr_id0 + (index_type)m_rp.m_lower[0]; + if (offset_0 < m_rp.m_upper[0] && thr_id0 < m_rp.m_tile[0]) { + for (index_type j = tile_id1; j < m_rp.m_tile_end[1]; j += numbl1) { + const index_type offset_1 = + j * m_rp.m_tile[1] + thr_id1 + (index_type)m_rp.m_lower[1]; + if (offset_1 < m_rp.m_upper[1] && thr_id1 < m_rp.m_tile[1]) { + for (index_type k = tile_id2; k < m_rp.m_tile_end[2]; + k += numbl2) { + const index_type offset_2 = + k * m_rp.m_tile[2] + thr_id2 + (index_type)m_rp.m_lower[2]; + if (offset_2 < m_rp.m_upper[2] && thr_id2 < m_rp.m_tile[2]) { + for (index_type l = tile_id3; l < m_rp.m_tile_end[3]; + l += numbl3) { + const index_type offset_3 = l * m_rp.m_tile[3] + thr_id3 + + (index_type)m_rp.m_lower[3]; + if (offset_3 < m_rp.m_upper[3] && + thr_id3 < m_rp.m_tile[3]) { + for (index_type m = tile_id4; m < m_rp.m_tile_end[4]; + m += numbl4) { + const index_type offset_4 = m * m_rp.m_tile[4] + + thr_id4 + + (index_type)m_rp.m_lower[4]; + if (offset_4 < m_rp.m_upper[4] && + thr_id4 < m_rp.m_tile[4]) { + for (index_type n = tile_id5; n < m_rp.m_tile_end[5]; + n += numbl5) { + const index_type offset_5 = + n * m_rp.m_tile[5] + thr_id5 + + (index_type)m_rp.m_lower[5]; + if (offset_5 < m_rp.m_upper[5] && + thr_id5 < m_rp.m_tile[5]) { + m_func(Tag(), offset_0, offset_1, offset_2, + offset_3, offset_4, offset_5); } } } @@ -1124,168 +1311,175 @@ struct DeviceIterateTile<6,RP,Functor,Tag> } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; }; -} // Refactor +} // namespace Refactor // ---------------------------------------------------------------------------------- namespace Reduce { -template < typename T > -using is_void = std::is_same< T, void >; +template +using is_void = std::is_same; -template < typename T > -struct is_array_type : std::false_type -{ +template +struct is_array_type : std::false_type { using value_type = T; }; -template < typename T > -struct is_array_type< T* > : std::true_type -{ +template +struct is_array_type : std::true_type { using value_type = T; }; -template < typename T > -struct is_array_type< T[] > : std::true_type -{ +template +struct is_array_type : std::true_type { using value_type = T; }; // ------------------------------------------------------------------ // -template< int N , typename RP , typename Functor , typename Tag , typename ValueType , typename Enable = void > +template struct DeviceIterateTile; // ParallelReduce iteration pattern // Scalar reductions -// num_blocks = min( num_tiles, max_num_blocks ); //i.e. determined by number of tiles and reduction algorithm constraints -// extract n-dim tile offsets (i.e. tile's global starting mulit-index) from the tileid = blockid using tile dimensions -// local indices within a tile extracted from (index_type)threadIdx.x using tile dims, constrained by blocksize -// combine tile and local id info for multi-dim global ids +// num_blocks = min( num_tiles, max_num_blocks ); //i.e. determined by number of +// tiles and reduction algorithm constraints extract n-dim tile offsets (i.e. +// tile's global starting mulit-index) from the tileid = blockid using tile +// dimensions local indices within a tile extracted from (index_type)threadIdx.x +// using tile dims, constrained by blocksize combine tile and local id info for +// multi-dim global ids // Pattern: -// Each block+thread is responsible for a tile+local_id combo (additional when striding by num_blocks) +// Each block+thread is responsible for a tile+local_id combo (additional when +// striding by num_blocks) // 1. create offset arrays -// 2. loop over number of tiles, striding by griddim (equal to num tiles, or max num blocks) +// 2. loop over number of tiles, striding by griddim (equal to num tiles, or max +// num blocks) // 3. temps set for tile_idx and thrd_idx, which will be modified // 4. if LL vs LR: // determine tile starting point offsets (multidim) // determine local index offsets (multidim) // concatentate tile offset + local offset for global multi-dim index -// if offset withinin range bounds AND local offset within tile bounds, call functor +// if offset withinin range bounds AND local offset within tile bounds, call +// functor // ValueType = T -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<2,RP,Functor,void,ValueType, typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<2,RP,Functor,Tag, ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<3,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<3,RP,Functor,Tag, ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1534,58 +1754,64 @@ struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1611,59 +1841,64 @@ struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< !i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1689,58 +1928,64 @@ struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1766,59 +2015,64 @@ struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< !i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< !is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1844,58 +2102,64 @@ struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< !is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , ValueType & v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, ValueType& v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -1921,130 +2189,138 @@ struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< !i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; - ValueType & m_v; + private: + const RP& m_rp; + const Functor& m_func; + ValueType& m_v; }; - // ValueType = T[], T* -//Rank 2 +// Rank 2 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<2,RP,Functor,void,ValueType, typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<2,RP,Functor,Tag, ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 2, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2070,128 +2349,139 @@ struct DeviceIterateTile<2,RP,Functor,Tag, ValueType, typename std::enable_if< i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_v); + } } - } //end for loop over num_tiles - product of tiles in each direction + } // end for loop over num_tiles - product of tiles in each direction } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 3 +// Rank 3 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<3,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y - m_local_offset[i] = (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, add to m_offset right away + m_local_offset[i] = + (thrd_idx % m_rp.m_tile[i]); // Move this to first computation, + // add to m_offset right away thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<3,RP,Functor,Tag, ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 3, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; - - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} - - inline __device__ - void exec_range() const - { - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + using value_type = typename is_array_type::value_type; + + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} + + inline __device__ void exec_range() const { + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2217,60 +2510,64 @@ struct DeviceIterateTile<3,RP,Functor,Tag, ValueType, typename std::enable_if< i thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 4 +// Rank 4 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2296,59 +2596,65 @@ struct DeviceIterateTile<4,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for void tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 4, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - inline __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + inline __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, + value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2374,60 +2684,65 @@ struct DeviceIterateTile<4,RP,Functor,Tag,ValueType, typename std::enable_if< is thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 5 +// Rank 5 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2453,59 +2772,65 @@ struct DeviceIterateTile<5,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 5, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2531,60 +2860,65 @@ struct DeviceIterateTile<5,RP,Functor,Tag,ValueType, typename std::enable_if< is thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - -//Rank 6 +// Rank 6 // Specializations for void tag type -template< typename RP , typename Functor , typename ValueType > -struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< is_array_type::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, void, ValueType, + typename std::enable_if::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2610,59 +2948,65 @@ struct DeviceIterateTile<6,RP,Functor,void,ValueType , typename std::enable_if< thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; - // Specializations for tag type -template< typename RP , typename Functor , typename Tag, typename ValueType > -struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< is_array_type::value && !is_void< Tag >::value >::type > -{ +template +struct DeviceIterateTile< + 6, RP, Functor, Tag, ValueType, + typename std::enable_if::value && + !is_void::value>::type> { using index_type = typename RP::index_type; - using value_type = typename is_array_type< ValueType >::value_type; + using value_type = typename is_array_type::value_type; - __device__ - DeviceIterateTile( const RP & rp_ , const Functor & f_ , value_type* v_) - : m_rp(rp_) - , m_func(f_) - , m_v(v_) - {} + __device__ DeviceIterateTile(const RP& rp_, const Functor& f_, value_type* v_) + : m_rp(rp_), m_func(f_), m_v(v_) {} static constexpr index_type max_blocks = 65535; - //static constexpr index_type max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); - - inline __device__ - void exec_range() const - { - //enum { max_blocks = static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; - //const index_type max_blocks = static_cast( Kokkos::Impl::cuda_internal_maximum_grid_count() ); - if ( (index_type)blockIdx.x < m_rp.m_num_tiles && (index_type)threadIdx.y < m_rp.m_prod_tile_dims ) { - index_type m_offset[RP::rank]; // tile starting global id offset - index_type m_local_offset[RP::rank]; // tile starting global id offset - - for ( index_type tileidx = (index_type)blockIdx.x; tileidx < m_rp.m_num_tiles; tileidx += gridDim.x ) { - index_type tile_idx = tileidx; // temp because tile_idx will be modified while determining tile starting point offsets + // static constexpr index_type max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount); + + inline __device__ void exec_range() const { + // enum { max_blocks = + // static_cast(Kokkos::Impl::CudaTraits::UpperBoundGridCount) }; + // const index_type max_blocks = static_cast( + // Kokkos::Impl::cuda_internal_maximum_grid_count() ); + if ((index_type)blockIdx.x < m_rp.m_num_tiles && + (index_type)threadIdx.y < m_rp.m_prod_tile_dims) { + index_type m_offset[RP::rank]; // tile starting global id offset + index_type m_local_offset[RP::rank]; // tile starting global id offset + + for (index_type tileidx = (index_type)blockIdx.x; + tileidx < m_rp.m_num_tiles; tileidx += gridDim.x) { + index_type tile_idx = + tileidx; // temp because tile_idx will be modified while + // determining tile starting point offsets index_type thrd_idx = (index_type)threadIdx.y; - bool in_bounds = true; + bool in_bounds = true; // LL if (RP::inner_direction == RP::Left) { - for (int i=0; i=0; --i) { - m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + m_rp.m_lower[i] ; + for (int i = RP::rank - 1; i >= 0; --i) { + m_offset[i] = (tile_idx % m_rp.m_tile_end[i]) * m_rp.m_tile[i] + + m_rp.m_lower[i]; tile_idx /= m_rp.m_tile_end[i]; // tile-local indices identified with (index_type)threadIdx.y @@ -2688,28 +3036,32 @@ struct DeviceIterateTile<6,RP,Functor,Tag,ValueType, typename std::enable_if< is thrd_idx /= m_rp.m_tile[i]; m_offset[i] += m_local_offset[i]; - if ( !(m_offset[i] < m_rp.m_upper[i] && m_local_offset[i] < m_rp.m_tile[i]) ) { + if (!(m_offset[i] < m_rp.m_upper[i] && + m_local_offset[i] < m_rp.m_tile[i])) { in_bounds &= false; } } - if ( in_bounds ) - { m_func( Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], m_offset[4], m_offset[5], m_v ); } + if (in_bounds) { + m_func(Tag(), m_offset[0], m_offset[1], m_offset[2], m_offset[3], + m_offset[4], m_offset[5], m_v); + } } } } - } //end exec_range + } // end exec_range -private: - const RP & m_rp; - const Functor & m_func; + private: + const RP& m_rp; + const Functor& m_func; value_type* m_v; }; -} // Reduce +} // namespace Reduce // ---------------------------------------------------------------------------------- -} } //end namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos #endif #endif diff --git a/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp b/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp index 4c9ed47085..24be022d24 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_CudaSpace.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,12 +58,12 @@ //#include #include +#include #if defined(KOKKOS_ENABLE_PROFILING) #include #endif - /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -71,68 +72,82 @@ namespace Impl { namespace { - static std::atomic num_uvm_allocations(0) ; +static std::atomic num_uvm_allocations(0); - cudaStream_t get_deep_copy_stream() { - static cudaStream_t s = 0; - if( s == 0) { - cudaStreamCreate ( &s ); - } - return s; - } +cudaStream_t get_deep_copy_stream() { + static cudaStream_t s = 0; + if (s == 0) { + cudaStreamCreate(&s); + } + return s; } +} // namespace -DeepCopy::DeepCopy( void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpy( dst , src , n , cudaMemcpyDefault ) ); } +DeepCopy::DeepCopy(void *dst, const void *src, + size_t n) { + CUDA_SAFE_CALL(cudaMemcpy(dst, src, n, cudaMemcpyDefault)); +} -DeepCopy::DeepCopy( void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpy( dst , src , n , cudaMemcpyDefault ) ); } +DeepCopy::DeepCopy(void *dst, const void *src, + size_t n) { + CUDA_SAFE_CALL(cudaMemcpy(dst, src, n, cudaMemcpyDefault)); +} -DeepCopy::DeepCopy( void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpy( dst , src , n , cudaMemcpyDefault ) ); } +DeepCopy::DeepCopy(void *dst, const void *src, + size_t n) { + CUDA_SAFE_CALL(cudaMemcpy(dst, src, n, cudaMemcpyDefault)); +} -DeepCopy::DeepCopy( const Cuda & instance , void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , instance.cuda_stream() ) ); } +DeepCopy::DeepCopy(const Cuda &instance, void *dst, + const void *src, size_t n) { + CUDA_SAFE_CALL( + cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, instance.cuda_stream())); +} -DeepCopy::DeepCopy( const Cuda & instance , void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , instance.cuda_stream() ) ); } +DeepCopy::DeepCopy(const Cuda &instance, void *dst, + const void *src, size_t n) { + CUDA_SAFE_CALL( + cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, instance.cuda_stream())); +} -DeepCopy::DeepCopy( const Cuda & instance , void * dst , const void * src , size_t n ) -{ CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , instance.cuda_stream() ) ); } +DeepCopy::DeepCopy(const Cuda &instance, void *dst, + const void *src, size_t n) { + CUDA_SAFE_CALL( + cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, instance.cuda_stream())); +} -void DeepCopyAsyncCuda( void * dst , const void * src , size_t n) { +void DeepCopyAsyncCuda(void *dst, const void *src, size_t n) { cudaStream_t s = get_deep_copy_stream(); - CUDA_SAFE_CALL( cudaMemcpyAsync( dst , src , n , cudaMemcpyDefault , s ) ); + CUDA_SAFE_CALL(cudaMemcpyAsync(dst, src, n, cudaMemcpyDefault, s)); cudaStreamSynchronize(s); } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ - namespace Kokkos { -void CudaSpace::access_error() -{ - const std::string msg("Kokkos::CudaSpace::access_error attempt to execute Cuda function from non-Cuda space" ); - Kokkos::Impl::throw_runtime_exception( msg ); +void CudaSpace::access_error() { + const std::string msg( + "Kokkos::CudaSpace::access_error attempt to execute Cuda function from " + "non-Cuda space"); + Kokkos::Impl::throw_runtime_exception(msg); } -void CudaSpace::access_error( const void * const ) -{ - const std::string msg("Kokkos::CudaSpace::access_error attempt to execute Cuda function from non-Cuda space" ); - Kokkos::Impl::throw_runtime_exception( msg ); +void CudaSpace::access_error(const void *const) { + const std::string msg( + "Kokkos::CudaSpace::access_error attempt to execute Cuda function from " + "non-Cuda space"); + Kokkos::Impl::throw_runtime_exception(msg); } - /*--------------------------------------------------------------------------*/ -bool CudaUVMSpace::available() -{ -#if defined( CUDA_VERSION ) && ( 6000 <= CUDA_VERSION ) && !defined(__APPLE__) +bool CudaUVMSpace::available() { +#if defined(CUDA_VERSION) && (6000 <= CUDA_VERSION) && !defined(__APPLE__) enum { UVM_available = true }; #else enum { UVM_available = false }; @@ -142,99 +157,155 @@ bool CudaUVMSpace::available() /*--------------------------------------------------------------------------*/ -int CudaUVMSpace::number_of_allocations() -{ +int CudaUVMSpace::number_of_allocations() { return Kokkos::Impl::num_uvm_allocations.load(); } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST +// The purpose of the following variable is to allow a state-based choice +// for pinning UVM allocations to the CPU. For now this is considered +// an experimental debugging capability - with the potential to work around +// some CUDA issues. +bool CudaUVMSpace::kokkos_impl_cuda_pin_uvm_to_host_v = false; -} // namespace Kokkos +bool CudaUVMSpace::cuda_pin_uvm_to_host() { + return CudaUVMSpace::kokkos_impl_cuda_pin_uvm_to_host_v; +} +void CudaUVMSpace::cuda_set_pin_uvm_to_host(bool val) { + CudaUVMSpace::kokkos_impl_cuda_pin_uvm_to_host_v = val; +} +#endif +} // namespace Kokkos + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST +bool kokkos_impl_cuda_pin_uvm_to_host() { + return Kokkos::CudaUVMSpace::cuda_pin_uvm_to_host(); +} + +void kokkos_impl_cuda_set_pin_uvm_to_host(bool val) { + Kokkos::CudaUVMSpace::cuda_set_pin_uvm_to_host(val); +} +#endif /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ namespace Kokkos { -CudaSpace::CudaSpace() - : m_device( Kokkos::Cuda().cuda_device() ) -{ -} +CudaSpace::CudaSpace() : m_device(Kokkos::Cuda().cuda_device()) {} -CudaUVMSpace::CudaUVMSpace() - : m_device( Kokkos::Cuda().cuda_device() ) -{ -} +CudaUVMSpace::CudaUVMSpace() : m_device(Kokkos::Cuda().cuda_device()) {} -CudaHostPinnedSpace::CudaHostPinnedSpace() -{ -} +CudaHostPinnedSpace::CudaHostPinnedSpace() {} -void * CudaSpace::allocate( const size_t arg_alloc_size ) const -{ - void * ptr = NULL; +//============================================================================== +// {{{1 - CUDA_SAFE_CALL( cudaMalloc( &ptr, arg_alloc_size ) ); +void *CudaSpace::allocate(const size_t arg_alloc_size) const { + void *ptr = nullptr; - return ptr ; + auto error_code = cudaMalloc(&ptr, arg_alloc_size); + if (error_code != cudaSuccess) { // TODO tag as unlikely branch + cudaGetLastError(); // This is the only way to clear the last error, which + // we should do here since we're turning it into an + // exception here + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, error_code, + Experimental::RawMemoryAllocationFailure::AllocationMechanism:: + CudaMalloc); + } + return ptr; } -void * CudaUVMSpace::allocate( const size_t arg_alloc_size ) const -{ - void * ptr = NULL; +void *CudaUVMSpace::allocate(const size_t arg_alloc_size) const { + void *ptr = nullptr; enum { max_uvm_allocations = 65536 }; Cuda::impl_static_fence(); - if ( arg_alloc_size > 0 ) - { + if (arg_alloc_size > 0) { Kokkos::Impl::num_uvm_allocations++; - if ( Kokkos::Impl::num_uvm_allocations.load() > max_uvm_allocations ) { - Kokkos::Impl::throw_runtime_exception( "CudaUVM error: The maximum limit of UVM allocations exceeded (currently 65536)." ) ; + if (Kokkos::Impl::num_uvm_allocations.load() > max_uvm_allocations) { + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, 1, + Experimental::RawMemoryAllocationFailure::FailureMode:: + MaximumCudaUVMAllocationsExceeded); } - CUDA_SAFE_CALL( cudaMallocManaged( &ptr, arg_alloc_size , cudaMemAttachGlobal ) ); + auto error_code = + cudaMallocManaged(&ptr, arg_alloc_size, cudaMemAttachGlobal); + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST + if (Kokkos::CudaUVMSpace::cuda_pin_uvm_to_host()) + cudaMemAdvise(ptr, arg_alloc_size, cudaMemAdviseSetPreferredLocation, + cudaCpuDeviceId); +#endif + + if (error_code != cudaSuccess) { // TODO tag as unlikely branch + cudaGetLastError(); // This is the only way to clear the last error, + // which we should do here since we're turning it + // into an exception here + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, error_code, + Experimental::RawMemoryAllocationFailure::AllocationMechanism:: + CudaMallocManaged); + } } Cuda::impl_static_fence(); - return ptr ; + return ptr; } -void * CudaHostPinnedSpace::allocate( const size_t arg_alloc_size ) const -{ - void * ptr = NULL; +void *CudaHostPinnedSpace::allocate(const size_t arg_alloc_size) const { + void *ptr = nullptr; - CUDA_SAFE_CALL( cudaHostAlloc( &ptr, arg_alloc_size , cudaHostAllocDefault ) ); + auto error_code = cudaHostAlloc(&ptr, arg_alloc_size, cudaHostAllocDefault); + if (error_code != cudaSuccess) { // TODO tag as unlikely branch + cudaGetLastError(); // This is the only way to clear the last error, which + // we should do here since we're turning it into an + // exception here + throw Experimental::CudaRawMemoryAllocationFailure( + arg_alloc_size, error_code, + Experimental::RawMemoryAllocationFailure::AllocationMechanism:: + CudaHostAlloc); + } - return ptr ; + return ptr; } -void CudaSpace::deallocate( void * const arg_alloc_ptr , const size_t /* arg_alloc_size */ ) const -{ +// end allocate() }}}1 +//============================================================================== + +void CudaSpace::deallocate(void *const arg_alloc_ptr, + const size_t /* arg_alloc_size */) const { try { - CUDA_SAFE_CALL( cudaFree( arg_alloc_ptr ) ); - } catch(...) {} + CUDA_SAFE_CALL(cudaFree(arg_alloc_ptr)); + } catch (...) { + } } -void CudaUVMSpace::deallocate( void * const arg_alloc_ptr , const size_t /* arg_alloc_size */ ) const -{ +void CudaUVMSpace::deallocate(void *const arg_alloc_ptr, + const size_t /* arg_alloc_size */) const { Cuda::impl_static_fence(); try { - if ( arg_alloc_ptr != nullptr ) { + if (arg_alloc_ptr != nullptr) { Kokkos::Impl::num_uvm_allocations--; - CUDA_SAFE_CALL( cudaFree( arg_alloc_ptr ) ); + CUDA_SAFE_CALL(cudaFree(arg_alloc_ptr)); } - } catch(...) {} + } catch (...) { + } Cuda::impl_static_fence(); } -void CudaHostPinnedSpace::deallocate( void * const arg_alloc_ptr , const size_t /* arg_alloc_size */ ) const -{ +void CudaHostPinnedSpace::deallocate(void *const arg_alloc_ptr, + const size_t /* arg_alloc_size */) const { try { - CUDA_SAFE_CALL( cudaFreeHost( arg_alloc_ptr ) ); - } catch(...) {} + CUDA_SAFE_CALL(cudaFreeHost(arg_alloc_ptr)); + } catch (...) { + } } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -243,606 +314,611 @@ namespace Kokkos { namespace Impl { #ifdef KOKKOS_DEBUG -SharedAllocationRecord< void , void > -SharedAllocationRecord< Kokkos::CudaSpace , void >::s_root_record ; +SharedAllocationRecord + SharedAllocationRecord::s_root_record; -SharedAllocationRecord< void , void > -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::s_root_record ; +SharedAllocationRecord + SharedAllocationRecord::s_root_record; -SharedAllocationRecord< void , void > -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::s_root_record ; +SharedAllocationRecord + SharedAllocationRecord::s_root_record; #endif ::cudaTextureObject_t -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -attach_texture_object( const unsigned sizeof_alias - , void * const alloc_ptr - , size_t const alloc_size ) -{ +SharedAllocationRecord::attach_texture_object( + const unsigned sizeof_alias, void *const alloc_ptr, + size_t const alloc_size) { enum { TEXTURE_BOUND_1D = 1u << 27 }; - if ( ( alloc_ptr == 0 ) || ( sizeof_alias * TEXTURE_BOUND_1D <= alloc_size ) ) { - std::ostringstream msg ; + if ((alloc_ptr == 0) || (sizeof_alias * TEXTURE_BOUND_1D <= alloc_size)) { + std::ostringstream msg; msg << "Kokkos::CudaSpace ERROR: Cannot attach texture object to" << " alloc_ptr(" << alloc_ptr << ")" << " alloc_size(" << alloc_size << ")" - << " max_size(" << ( sizeof_alias * TEXTURE_BOUND_1D ) << ")" ; - std::cerr << msg.str() << std::endl ; + << " max_size(" << (sizeof_alias * TEXTURE_BOUND_1D) << ")"; + std::cerr << msg.str() << std::endl; std::cerr.flush(); - Kokkos::Impl::throw_runtime_exception( msg.str() ); + Kokkos::Impl::throw_runtime_exception(msg.str()); } - ::cudaTextureObject_t tex_obj ; + ::cudaTextureObject_t tex_obj; - struct cudaResourceDesc resDesc ; - struct cudaTextureDesc texDesc ; + struct cudaResourceDesc resDesc; + struct cudaTextureDesc texDesc; - memset( & resDesc , 0 , sizeof(resDesc) ); - memset( & texDesc , 0 , sizeof(texDesc) ); + memset(&resDesc, 0, sizeof(resDesc)); + memset(&texDesc, 0, sizeof(texDesc)); - resDesc.resType = cudaResourceTypeLinear ; - resDesc.res.linear.desc = ( sizeof_alias == 4 ? cudaCreateChannelDesc< int >() : - ( sizeof_alias == 8 ? cudaCreateChannelDesc< ::int2 >() : - /* sizeof_alias == 16 */ cudaCreateChannelDesc< ::int4 >() ) ); - resDesc.res.linear.sizeInBytes = alloc_size ; - resDesc.res.linear.devPtr = alloc_ptr ; + resDesc.resType = cudaResourceTypeLinear; + resDesc.res.linear.desc = + (sizeof_alias == 4 + ? cudaCreateChannelDesc() + : (sizeof_alias == 8 + ? cudaCreateChannelDesc< ::int2>() + : + /* sizeof_alias == 16 */ cudaCreateChannelDesc< ::int4>())); + resDesc.res.linear.sizeInBytes = alloc_size; + resDesc.res.linear.devPtr = alloc_ptr; - CUDA_SAFE_CALL( cudaCreateTextureObject( & tex_obj , & resDesc, & texDesc, NULL ) ); + CUDA_SAFE_CALL(cudaCreateTextureObject(&tex_obj, &resDesc, &texDesc, NULL)); - return tex_obj ; + return tex_obj; } -std::string -SharedAllocationRecord< Kokkos::CudaSpace , void >::get_label() const -{ - SharedAllocationHeader header ; +//============================================================================== +// {{{1 - Kokkos::Impl::DeepCopy< Kokkos::HostSpace , Kokkos::CudaSpace >( & header , RecordBase::head() , sizeof(SharedAllocationHeader) ); +std::string SharedAllocationRecord::get_label() const { + SharedAllocationHeader header; - return std::string( header.m_label ); + Kokkos::Impl::DeepCopy( + &header, RecordBase::head(), sizeof(SharedAllocationHeader)); + + return std::string(header.m_label); } -std::string -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::get_label() const -{ - return std::string( RecordBase::head()->m_label ); +std::string SharedAllocationRecord::get_label() + const { + return std::string(RecordBase::head()->m_label); } std::string -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::get_label() const -{ - return std::string( RecordBase::head()->m_label ); +SharedAllocationRecord::get_label() const { + return std::string(RecordBase::head()->m_label); } -SharedAllocationRecord< Kokkos::CudaSpace , void > * -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -allocate( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) -{ - return new SharedAllocationRecord( arg_space , arg_label , arg_alloc_size ); +// end SharedAllocationRecord::get_label() }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + +SharedAllocationRecord + *SharedAllocationRecord::allocate( + const Kokkos::CudaSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size) { + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); } -SharedAllocationRecord< Kokkos::CudaUVMSpace , void > * -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -allocate( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) -{ - return new SharedAllocationRecord( arg_space , arg_label , arg_alloc_size ); +SharedAllocationRecord + *SharedAllocationRecord::allocate( + const Kokkos::CudaUVMSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size) { + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); } -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > * -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -allocate( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) -{ - return new SharedAllocationRecord( arg_space , arg_label , arg_alloc_size ); +SharedAllocationRecord + *SharedAllocationRecord::allocate( + const Kokkos::CudaHostPinnedSpace &arg_space, + const std::string &arg_label, const size_t arg_alloc_size) { + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); } -void -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -deallocate( SharedAllocationRecord< void , void > * arg_rec ) -{ - delete static_cast(arg_rec); +// end SharedAllocationRecord allocate() }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + +void SharedAllocationRecord::deallocate( + SharedAllocationRecord *arg_rec) { + delete static_cast(arg_rec); } -void -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -deallocate( SharedAllocationRecord< void , void > * arg_rec ) -{ - delete static_cast(arg_rec); +void SharedAllocationRecord::deallocate( + SharedAllocationRecord *arg_rec) { + delete static_cast(arg_rec); } -void -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -deallocate( SharedAllocationRecord< void , void > * arg_rec ) -{ - delete static_cast(arg_rec); +void SharedAllocationRecord::deallocate( + SharedAllocationRecord *arg_rec) { + delete static_cast(arg_rec); } -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -~SharedAllocationRecord() -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { +// end SharedAllocationRecord deallocate }}}1 +//============================================================================== - SharedAllocationHeader header ; - Kokkos::Impl::DeepCopy( & header , RecordBase::m_alloc_ptr , sizeof(SharedAllocationHeader) ); +//============================================================================== +// {{{1 + +SharedAllocationRecord::~SharedAllocationRecord() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + SharedAllocationHeader header; + Kokkos::Impl::DeepCopy( + &header, RecordBase::m_alloc_ptr, sizeof(SharedAllocationHeader)); Kokkos::Profiling::deallocateData( - Kokkos::Profiling::SpaceHandle(Kokkos::CudaSpace::name()),header.m_label, - data(),size()); + Kokkos::Profiling::SpaceHandle(Kokkos::CudaSpace::name()), + header.m_label, data(), size()); } - #endif +#endif - m_space.deallocate( SharedAllocationRecord< void , void >::m_alloc_ptr - , SharedAllocationRecord< void , void >::m_alloc_size - ); + m_space.deallocate(SharedAllocationRecord::m_alloc_ptr, + SharedAllocationRecord::m_alloc_size); } -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -~SharedAllocationRecord() -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Cuda::impl_static_fence(); //Make sure I can access the label ... +SharedAllocationRecord::~SharedAllocationRecord() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Cuda::impl_static_fence(); // Make sure I can access the label ... Kokkos::Profiling::deallocateData( - Kokkos::Profiling::SpaceHandle(Kokkos::CudaUVMSpace::name()),RecordBase::m_alloc_ptr->m_label, - data(),size()); + Kokkos::Profiling::SpaceHandle(Kokkos::CudaUVMSpace::name()), + RecordBase::m_alloc_ptr->m_label, data(), size()); } - #endif +#endif - m_space.deallocate( SharedAllocationRecord< void , void >::m_alloc_ptr - , SharedAllocationRecord< void , void >::m_alloc_size - ); + m_space.deallocate(SharedAllocationRecord::m_alloc_ptr, + SharedAllocationRecord::m_alloc_size); } -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -~SharedAllocationRecord() -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { +SharedAllocationRecord::~SharedAllocationRecord() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::deallocateData( - Kokkos::Profiling::SpaceHandle(Kokkos::CudaHostPinnedSpace::name()),RecordBase::m_alloc_ptr->m_label, - data(),size()); + Kokkos::Profiling::SpaceHandle(Kokkos::CudaHostPinnedSpace::name()), + RecordBase::m_alloc_ptr->m_label, data(), size()); } - #endif - - m_space.deallocate( SharedAllocationRecord< void , void >::m_alloc_ptr - , SharedAllocationRecord< void , void >::m_alloc_size - ); -} - -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -SharedAllocationRecord( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const SharedAllocationRecord< void , void >::function_type arg_dealloc - ) - // Pass through allocated [ SharedAllocationHeader , user_memory ] - // Pass through deallocation function - : SharedAllocationRecord< void , void > - ( +#endif + + m_space.deallocate(SharedAllocationRecord::m_alloc_ptr, + SharedAllocationRecord::m_alloc_size); +} + +// end SharedAllocationRecord destructors }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + +SharedAllocationRecord::SharedAllocationRecord( + const Kokkos::CudaSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size, + const SharedAllocationRecord::function_type arg_dealloc) + // Pass through allocated [ SharedAllocationHeader , user_memory ] + // Pass through deallocation function + : SharedAllocationRecord( #ifdef KOKKOS_DEBUG - & SharedAllocationRecord< Kokkos::CudaSpace , void >::s_root_record, + &SharedAllocationRecord::s_root_record, #endif - reinterpret_cast( arg_space.allocate( sizeof(SharedAllocationHeader) + arg_alloc_size ) ) - , sizeof(SharedAllocationHeader) + arg_alloc_size - , arg_dealloc - ) - , m_tex_obj( 0 ) - , m_space( arg_space ) -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::allocateData(Kokkos::Profiling::SpaceHandle(arg_space.name()),arg_label,data(),arg_alloc_size); + Impl::checked_allocation_with_header(arg_space, arg_label, + arg_alloc_size), + sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc), + m_tex_obj(0), + m_space(arg_space) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::allocateData( + Kokkos::Profiling::SpaceHandle(arg_space.name()), arg_label, data(), + arg_alloc_size); } - #endif +#endif - SharedAllocationHeader header ; + SharedAllocationHeader header; // Fill in the Header information - header.m_record = static_cast< SharedAllocationRecord< void , void > * >( this ); + header.m_record = static_cast *>(this); - strncpy( header.m_label - , arg_label.c_str() - , SharedAllocationHeader::maximum_label_length - ); + strncpy(header.m_label, arg_label.c_str(), + SharedAllocationHeader::maximum_label_length); // Set last element zero, in case c_str is too long - header.m_label[SharedAllocationHeader::maximum_label_length - 1] = (char) 0; + header.m_label[SharedAllocationHeader::maximum_label_length - 1] = (char)0; // Copy to device memory - Kokkos::Impl::DeepCopy( RecordBase::m_alloc_ptr , & header , sizeof(SharedAllocationHeader) ); -} - -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -SharedAllocationRecord( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const SharedAllocationRecord< void , void >::function_type arg_dealloc - ) - // Pass through allocated [ SharedAllocationHeader , user_memory ] - // Pass through deallocation function - : SharedAllocationRecord< void , void > - ( + Kokkos::Impl::DeepCopy(RecordBase::m_alloc_ptr, &header, + sizeof(SharedAllocationHeader)); +} + +SharedAllocationRecord::SharedAllocationRecord( + const Kokkos::CudaUVMSpace &arg_space, const std::string &arg_label, + const size_t arg_alloc_size, + const SharedAllocationRecord::function_type arg_dealloc) + // Pass through allocated [ SharedAllocationHeader , user_memory ] + // Pass through deallocation function + : SharedAllocationRecord( #ifdef KOKKOS_DEBUG - & SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::s_root_record, + &SharedAllocationRecord::s_root_record, #endif - reinterpret_cast( arg_space.allocate( sizeof(SharedAllocationHeader) + arg_alloc_size ) ) - , sizeof(SharedAllocationHeader) + arg_alloc_size - , arg_dealloc - ) - , m_tex_obj( 0 ) - , m_space( arg_space ) -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::allocateData(Kokkos::Profiling::SpaceHandle(arg_space.name()),arg_label,data(),arg_alloc_size); + Impl::checked_allocation_with_header(arg_space, arg_label, + arg_alloc_size), + sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc), + m_tex_obj(0), + m_space(arg_space) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::allocateData( + Kokkos::Profiling::SpaceHandle(arg_space.name()), arg_label, data(), + arg_alloc_size); } - #endif - // Fill in the Header information, directly accessible via UVM +#endif + // Fill in the Header information, directly accessible via UVM - RecordBase::m_alloc_ptr->m_record = this ; + RecordBase::m_alloc_ptr->m_record = this; - strncpy( RecordBase::m_alloc_ptr->m_label - , arg_label.c_str() - , SharedAllocationHeader::maximum_label_length - ); + strncpy(RecordBase::m_alloc_ptr->m_label, arg_label.c_str(), + SharedAllocationHeader::maximum_label_length); // Set last element zero, in case c_str is too long - RecordBase::m_alloc_ptr->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char) 0; -} - -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -SharedAllocationRecord( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const SharedAllocationRecord< void , void >::function_type arg_dealloc - ) - // Pass through allocated [ SharedAllocationHeader , user_memory ] - // Pass through deallocation function - : SharedAllocationRecord< void , void > - ( + RecordBase::m_alloc_ptr + ->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char)0; +} + +SharedAllocationRecord:: + SharedAllocationRecord( + const Kokkos::CudaHostPinnedSpace &arg_space, + const std::string &arg_label, const size_t arg_alloc_size, + const SharedAllocationRecord::function_type arg_dealloc) + // Pass through allocated [ SharedAllocationHeader , user_memory ] + // Pass through deallocation function + : SharedAllocationRecord( #ifdef KOKKOS_DEBUG - & SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::s_root_record, + &SharedAllocationRecord::s_root_record, #endif - reinterpret_cast( arg_space.allocate( sizeof(SharedAllocationHeader) + arg_alloc_size ) ) - , sizeof(SharedAllocationHeader) + arg_alloc_size - , arg_dealloc - ) - , m_space( arg_space ) -{ - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::allocateData(Kokkos::Profiling::SpaceHandle(arg_space.name()),arg_label,data(),arg_alloc_size); + Impl::checked_allocation_with_header(arg_space, arg_label, + arg_alloc_size), + sizeof(SharedAllocationHeader) + arg_alloc_size, arg_dealloc), + m_space(arg_space) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::allocateData( + Kokkos::Profiling::SpaceHandle(arg_space.name()), arg_label, data(), + arg_alloc_size); } - #endif - // Fill in the Header information, directly accessible via UVM +#endif + // Fill in the Header information, directly accessible on the host - RecordBase::m_alloc_ptr->m_record = this ; + RecordBase::m_alloc_ptr->m_record = this; - strncpy( RecordBase::m_alloc_ptr->m_label - , arg_label.c_str() - , SharedAllocationHeader::maximum_label_length - ); + strncpy(RecordBase::m_alloc_ptr->m_label, arg_label.c_str(), + SharedAllocationHeader::maximum_label_length); // Set last element zero, in case c_str is too long - RecordBase::m_alloc_ptr->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char) 0; + RecordBase::m_alloc_ptr + ->m_label[SharedAllocationHeader::maximum_label_length - 1] = (char)0; } -//---------------------------------------------------------------------------- +// end SharedAllocationRecord constructors }}}1 +//============================================================================== -void * SharedAllocationRecord< Kokkos::CudaSpace , void >:: -allocate_tracked( const Kokkos::CudaSpace & arg_space - , const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - if ( ! arg_alloc_size ) return (void *) 0 ; +//============================================================================== +// {{{1 - SharedAllocationRecord * const r = - allocate( arg_space , arg_alloc_label , arg_alloc_size ); +void *SharedAllocationRecord::allocate_tracked( + const Kokkos::CudaSpace &arg_space, const std::string &arg_alloc_label, + const size_t arg_alloc_size) { + if (!arg_alloc_size) return (void *)0; - RecordBase::increment( r ); + SharedAllocationRecord *const r = + allocate(arg_space, arg_alloc_label, arg_alloc_size); + + RecordBase::increment(r); return r->data(); } -void SharedAllocationRecord< Kokkos::CudaSpace , void >:: -deallocate_tracked( void * const arg_alloc_ptr ) -{ - if ( arg_alloc_ptr != 0 ) { - SharedAllocationRecord * const r = get_record( arg_alloc_ptr ); +void SharedAllocationRecord::deallocate_tracked( + void *const arg_alloc_ptr) { + if (arg_alloc_ptr != 0) { + SharedAllocationRecord *const r = get_record(arg_alloc_ptr); - RecordBase::decrement( r ); + RecordBase::decrement(r); } } -void * SharedAllocationRecord< Kokkos::CudaSpace , void >:: -reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) -{ - SharedAllocationRecord * const r_old = get_record( arg_alloc_ptr ); - SharedAllocationRecord * const r_new = allocate( r_old->m_space , r_old->get_label() , arg_alloc_size ); +void *SharedAllocationRecord::reallocate_tracked( + void *const arg_alloc_ptr, const size_t arg_alloc_size) { + SharedAllocationRecord *const r_old = get_record(arg_alloc_ptr); + SharedAllocationRecord *const r_new = + allocate(r_old->m_space, r_old->get_label(), arg_alloc_size); - Kokkos::Impl::DeepCopy( r_new->data() , r_old->data() - , std::min( r_old->size() , r_new->size() ) ); + Kokkos::Impl::DeepCopy( + r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size())); - RecordBase::increment( r_new ); - RecordBase::decrement( r_old ); + RecordBase::increment(r_new); + RecordBase::decrement(r_old); return r_new->data(); } -void * SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -allocate_tracked( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - if ( ! arg_alloc_size ) return (void *) 0 ; +void *SharedAllocationRecord::allocate_tracked( + const Kokkos::CudaUVMSpace &arg_space, const std::string &arg_alloc_label, + const size_t arg_alloc_size) { + if (!arg_alloc_size) return (void *)0; - SharedAllocationRecord * const r = - allocate( arg_space , arg_alloc_label , arg_alloc_size ); + SharedAllocationRecord *const r = + allocate(arg_space, arg_alloc_label, arg_alloc_size); - RecordBase::increment( r ); + RecordBase::increment(r); return r->data(); } -void SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -deallocate_tracked( void * const arg_alloc_ptr ) -{ - if ( arg_alloc_ptr != 0 ) { - - SharedAllocationRecord * const r = get_record( arg_alloc_ptr ); +void SharedAllocationRecord::deallocate_tracked( + void *const arg_alloc_ptr) { + if (arg_alloc_ptr != 0) { + SharedAllocationRecord *const r = get_record(arg_alloc_ptr); - RecordBase::decrement( r ); + RecordBase::decrement(r); } } -void * SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) -{ - SharedAllocationRecord * const r_old = get_record( arg_alloc_ptr ); - SharedAllocationRecord * const r_new = allocate( r_old->m_space , r_old->get_label() , arg_alloc_size ); +void *SharedAllocationRecord::reallocate_tracked( + void *const arg_alloc_ptr, const size_t arg_alloc_size) { + SharedAllocationRecord *const r_old = get_record(arg_alloc_ptr); + SharedAllocationRecord *const r_new = + allocate(r_old->m_space, r_old->get_label(), arg_alloc_size); - Kokkos::Impl::DeepCopy( r_new->data() , r_old->data() - , std::min( r_old->size() , r_new->size() ) ); + Kokkos::Impl::DeepCopy( + r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size())); - RecordBase::increment( r_new ); - RecordBase::decrement( r_old ); + RecordBase::increment(r_new); + RecordBase::decrement(r_old); return r_new->data(); } -void * SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -allocate_tracked( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - if ( ! arg_alloc_size ) return (void *) 0 ; +void * +SharedAllocationRecord::allocate_tracked( + const Kokkos::CudaHostPinnedSpace &arg_space, + const std::string &arg_alloc_label, const size_t arg_alloc_size) { + if (!arg_alloc_size) return (void *)0; - SharedAllocationRecord * const r = - allocate( arg_space , arg_alloc_label , arg_alloc_size ); + SharedAllocationRecord *const r = + allocate(arg_space, arg_alloc_label, arg_alloc_size); - RecordBase::increment( r ); + RecordBase::increment(r); return r->data(); } -void SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -deallocate_tracked( void * const arg_alloc_ptr ) -{ - if ( arg_alloc_ptr != 0 ) { - SharedAllocationRecord * const r = get_record( arg_alloc_ptr ); +void SharedAllocationRecord::deallocate_tracked(void *const + arg_alloc_ptr) { + if (arg_alloc_ptr != 0) { + SharedAllocationRecord *const r = get_record(arg_alloc_ptr); - RecordBase::decrement( r ); + RecordBase::decrement(r); } } -void * SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) -{ - SharedAllocationRecord * const r_old = get_record( arg_alloc_ptr ); - SharedAllocationRecord * const r_new = allocate( r_old->m_space , r_old->get_label() , arg_alloc_size ); +void * +SharedAllocationRecord::reallocate_tracked( + void *const arg_alloc_ptr, const size_t arg_alloc_size) { + SharedAllocationRecord *const r_old = get_record(arg_alloc_ptr); + SharedAllocationRecord *const r_new = + allocate(r_old->m_space, r_old->get_label(), arg_alloc_size); - Kokkos::Impl::DeepCopy( r_new->data() , r_old->data() - , std::min( r_old->size() , r_new->size() ) ); + Kokkos::Impl::DeepCopy( + r_new->data(), r_old->data(), std::min(r_old->size(), r_new->size())); - RecordBase::increment( r_new ); - RecordBase::decrement( r_old ); + RecordBase::increment(r_new); + RecordBase::decrement(r_old); return r_new->data(); } -//---------------------------------------------------------------------------- +// end SharedAllocationRecored::(re|de|)allocate_tracked }}}1 +//============================================================================== -SharedAllocationRecord< Kokkos::CudaSpace , void > * -SharedAllocationRecord< Kokkos::CudaSpace , void >::get_record( void * alloc_ptr ) -{ - using RecordCuda = SharedAllocationRecord< Kokkos::CudaSpace , void > ; +//============================================================================== +// {{{1 - using Header = SharedAllocationHeader ; +SharedAllocationRecord * +SharedAllocationRecord::get_record(void *alloc_ptr) { + using RecordCuda = SharedAllocationRecord; + + using Header = SharedAllocationHeader; // Copy the header from the allocation - Header head ; + Header head; - Header const * const head_cuda = alloc_ptr ? Header::get_header( alloc_ptr ) : (Header*) 0 ; + Header const *const head_cuda = + alloc_ptr ? Header::get_header(alloc_ptr) : (Header *)0; - if ( alloc_ptr ) { - Kokkos::Impl::DeepCopy( & head , head_cuda , sizeof(SharedAllocationHeader) ); + if (alloc_ptr) { + Kokkos::Impl::DeepCopy( + &head, head_cuda, sizeof(SharedAllocationHeader)); } - RecordCuda * const record = alloc_ptr ? static_cast< RecordCuda * >( head.m_record ) : (RecordCuda *) 0 ; + RecordCuda *const record = + alloc_ptr ? static_cast(head.m_record) : (RecordCuda *)0; - if ( ! alloc_ptr || record->m_alloc_ptr != head_cuda ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void >::get_record ERROR" ) ); + if (!alloc_ptr || record->m_alloc_ptr != head_cuda) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , " + "void >::get_record ERROR")); } - return record ; + return record; } -SharedAllocationRecord< Kokkos::CudaUVMSpace , void > * -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::get_record( void * alloc_ptr ) -{ - using Header = SharedAllocationHeader ; - using RecordCuda = SharedAllocationRecord< Kokkos::CudaUVMSpace , void > ; +SharedAllocationRecord *SharedAllocationRecord< + Kokkos::CudaUVMSpace, void>::get_record(void *alloc_ptr) { + using Header = SharedAllocationHeader; + using RecordCuda = SharedAllocationRecord; - Header * const h = alloc_ptr ? reinterpret_cast< Header * >( alloc_ptr ) - 1 : (Header *) 0 ; + Header *const h = + alloc_ptr ? reinterpret_cast
(alloc_ptr) - 1 : (Header *)0; - if ( ! alloc_ptr || h->m_record->m_alloc_ptr != h ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaUVMSpace , void >::get_record ERROR" ) ); + if (!alloc_ptr || h->m_record->m_alloc_ptr != h) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::SharedAllocationRecord< " + "Kokkos::CudaUVMSpace , void >::get_record ERROR")); } - return static_cast< RecordCuda * >( h->m_record ); + return static_cast(h->m_record); } -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > * -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::get_record( void * alloc_ptr ) -{ - using Header = SharedAllocationHeader ; - using RecordCuda = SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > ; +SharedAllocationRecord + *SharedAllocationRecord::get_record( + void *alloc_ptr) { + using Header = SharedAllocationHeader; + using RecordCuda = SharedAllocationRecord; - Header * const h = alloc_ptr ? reinterpret_cast< Header * >( alloc_ptr ) - 1 : (Header *) 0 ; + Header *const h = + alloc_ptr ? reinterpret_cast
(alloc_ptr) - 1 : (Header *)0; - if ( ! alloc_ptr || h->m_record->m_alloc_ptr != h ) { - Kokkos::Impl::throw_runtime_exception( std::string("Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >::get_record ERROR" ) ); + if (!alloc_ptr || h->m_record->m_alloc_ptr != h) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::SharedAllocationRecord< " + "Kokkos::CudaHostPinnedSpace , void >::get_record ERROR")); } - return static_cast< RecordCuda * >( h->m_record ); + return static_cast(h->m_record); } +// end SharedAllocationRecord::get_record() }}}1 +//============================================================================== + +//============================================================================== +// {{{1 + // Iterate records to print orphaned memory ... -void -SharedAllocationRecord< Kokkos::CudaSpace , void >:: -print_records( std::ostream & s , const Kokkos::CudaSpace & , bool detail ) -{ +void SharedAllocationRecord::print_records( + std::ostream &s, const Kokkos::CudaSpace &, bool detail) { #ifdef KOKKOS_DEBUG - SharedAllocationRecord< void , void > * r = & s_root_record ; + SharedAllocationRecord *r = &s_root_record; - char buffer[256] ; + char buffer[256]; - SharedAllocationHeader head ; + SharedAllocationHeader head; - if ( detail ) { + if (detail) { do { - if ( r->m_alloc_ptr ) { - Kokkos::Impl::DeepCopy( & head , r->m_alloc_ptr , sizeof(SharedAllocationHeader) ); - } - else { - head.m_label[0] = 0 ; + if (r->m_alloc_ptr) { + Kokkos::Impl::DeepCopy( + &head, r->m_alloc_ptr, sizeof(SharedAllocationHeader)); + } else { + head.m_label[0] = 0; } - //Formatting dependent on sizeof(uintptr_t) - const char * format_string; + // Formatting dependent on sizeof(uintptr_t) + const char *format_string; if (sizeof(uintptr_t) == sizeof(unsigned long)) { - format_string = "Cuda addr( 0x%.12lx ) list( 0x%.12lx 0x%.12lx ) extent[ 0x%.12lx + %.8ld ] count(%d) dealloc(0x%.12lx) %s\n"; - } - else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { - format_string = "Cuda addr( 0x%.12llx ) list( 0x%.12llx 0x%.12llx ) extent[ 0x%.12llx + %.8ld ] count(%d) dealloc(0x%.12llx) %s\n"; + format_string = + "Cuda addr( 0x%.12lx ) list( 0x%.12lx 0x%.12lx ) extent[ 0x%.12lx " + "+ %.8ld ] count(%d) dealloc(0x%.12lx) %s\n"; + } else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { + format_string = + "Cuda addr( 0x%.12llx ) list( 0x%.12llx 0x%.12llx ) extent[ " + "0x%.12llx + %.8ld ] count(%d) dealloc(0x%.12llx) %s\n"; } - snprintf( buffer , 256 - , format_string - , reinterpret_cast( r ) - , reinterpret_cast( r->m_prev ) - , reinterpret_cast( r->m_next ) - , reinterpret_cast( r->m_alloc_ptr ) - , r->m_alloc_size - , r->m_count - , reinterpret_cast( r->m_dealloc ) - , head.m_label - ); - s << buffer ; - r = r->m_next ; - } while ( r != & s_root_record ); - } - else { + snprintf(buffer, 256, format_string, reinterpret_cast(r), + reinterpret_cast(r->m_prev), + reinterpret_cast(r->m_next), + reinterpret_cast(r->m_alloc_ptr), r->m_alloc_size, + r->m_count, reinterpret_cast(r->m_dealloc), + head.m_label); + s << buffer; + r = r->m_next; + } while (r != &s_root_record); + } else { do { - if ( r->m_alloc_ptr ) { - - Kokkos::Impl::DeepCopy( & head , r->m_alloc_ptr , sizeof(SharedAllocationHeader) ); + if (r->m_alloc_ptr) { + Kokkos::Impl::DeepCopy( + &head, r->m_alloc_ptr, sizeof(SharedAllocationHeader)); - //Formatting dependent on sizeof(uintptr_t) - const char * format_string; + // Formatting dependent on sizeof(uintptr_t) + const char *format_string; if (sizeof(uintptr_t) == sizeof(unsigned long)) { format_string = "Cuda [ 0x%.12lx + %ld ] %s\n"; - } - else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { + } else if (sizeof(uintptr_t) == sizeof(unsigned long long)) { format_string = "Cuda [ 0x%.12llx + %ld ] %s\n"; } - snprintf( buffer , 256 - , format_string - , reinterpret_cast< uintptr_t >( r->data() ) - , r->size() - , head.m_label - ); - } - else { - snprintf( buffer , 256 , "Cuda [ 0 + 0 ]\n" ); + snprintf(buffer, 256, format_string, + reinterpret_cast(r->data()), r->size(), + head.m_label); + } else { + snprintf(buffer, 256, "Cuda [ 0 + 0 ]\n"); } - s << buffer ; - r = r->m_next ; - } while ( r != & s_root_record ); + s << buffer; + r = r->m_next; + } while (r != &s_root_record); } #else - Kokkos::Impl::throw_runtime_exception("SharedAllocationHeader::print_records only works with KOKKOS_DEBUG enabled"); + Kokkos::Impl::throw_runtime_exception( + "SharedAllocationHeader::print_records only works with " + "KOKKOS_DEBUG enabled"); #endif } -void -SharedAllocationRecord< Kokkos::CudaUVMSpace , void >:: -print_records( std::ostream & s , const Kokkos::CudaUVMSpace & , bool detail ) -{ +void SharedAllocationRecord::print_records( + std::ostream &s, const Kokkos::CudaUVMSpace &, bool detail) { #ifdef KOKKOS_DEBUG - SharedAllocationRecord< void , void >::print_host_accessible_records( s , "CudaUVM" , & s_root_record , detail ); + SharedAllocationRecord::print_host_accessible_records( + s, "CudaUVM", &s_root_record, detail); #else - Kokkos::Impl::throw_runtime_exception("SharedAllocationHeader::print_records only works with KOKKOS_DEBUG enabled"); + Kokkos::Impl::throw_runtime_exception( + "SharedAllocationHeader::print_records only works with " + "KOKKOS_DEBUG enabled"); #endif } -void -SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void >:: -print_records( std::ostream & s , const Kokkos::CudaHostPinnedSpace & , bool detail ) -{ +void SharedAllocationRecord::print_records( + std::ostream &s, const Kokkos::CudaHostPinnedSpace &, bool detail) { #ifdef KOKKOS_DEBUG - SharedAllocationRecord< void , void >::print_host_accessible_records( s , "CudaHostPinned" , & s_root_record , detail ); + SharedAllocationRecord::print_host_accessible_records( + s, "CudaHostPinned", &s_root_record, detail); #else - Kokkos::Impl::throw_runtime_exception("SharedAllocationHeader::print_records only works with KOKKOS_DEBUG enabled"); + Kokkos::Impl::throw_runtime_exception( + "SharedAllocationHeader::print_records only works with " + "KOKKOS_DEBUG enabled"); #endif } -void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink) { - static void* ptr = NULL; +// end SharedAllocationRecord::print_records() }}}1 +//============================================================================== + +void *cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink) { + static void *ptr = NULL; static std::int64_t current_size = 0; - if(current_size == 0) { + if (current_size == 0) { current_size = bytes; - ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory",current_size); + ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory", + current_size); } - if(bytes > current_size) { + if (bytes > current_size) { current_size = bytes; Kokkos::kokkos_free(ptr); - ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory",current_size); + ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory", + current_size); } - if((bytes < current_size) && (force_shrink)) { + if ((bytes < current_size) && (force_shrink)) { current_size = bytes; Kokkos::kokkos_free(ptr); - ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory",current_size); + ptr = Kokkos::kokkos_malloc("CudaSpace::ScratchMemory", + current_size); } return ptr; } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #else void KOKKOS_CORE_SRC_CUDA_CUDASPACE_PREVENT_LINK_ERROR() {} -#endif // KOKKOS_ENABLE_CUDA - +#endif // KOKKOS_ENABLE_CUDA diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp index 5726e02180..e76133fae8 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Alloc.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,13 +53,12 @@ namespace Kokkos { namespace Impl { -template< class DestructFunctor > -SharedAllocationRecord * -shared_allocation_record( Kokkos::CudaSpace const & arg_space - , void * const arg_alloc_ptr - , DestructFunctor const & arg_destruct ) -{ - SharedAllocationRecord * const record = SharedAllocationRecord::get_record( arg_alloc_ptr ); +template +SharedAllocationRecord* shared_allocation_record( + Kokkos::CudaSpace const& arg_space, void* const arg_alloc_ptr, + DestructFunctor const& arg_destruct) { + SharedAllocationRecord* const record = + SharedAllocationRecord::get_record(arg_alloc_ptr); // assert: record != 0 @@ -66,115 +66,88 @@ shared_allocation_record( Kokkos::CudaSpace const & arg_space // assert: record->m_destruct_function == 0 - DestructFunctor * const functor = - reinterpret_cast< DestructFunctor * >( - reinterpret_cast< uintptr_t >( record ) + sizeof(SharedAllocationRecord) ); + DestructFunctor* const functor = reinterpret_cast( + reinterpret_cast(record) + sizeof(SharedAllocationRecord)); - new( functor ) DestructFunctor( arg_destruct ); + new (functor) DestructFunctor(arg_destruct); - record->m_destruct_functor = & shared_allocation_destroy< DestructFunctor > ; + record->m_destruct_functor = &shared_allocation_destroy; - return record ; + return record; } - /// class CudaUnmanagedAllocator /// does nothing when deallocate(ptr,size) is called -struct CudaUnmanagedAllocator -{ - static const char * name() - { - return "Cuda Unmanaged Allocator"; - } +struct CudaUnmanagedAllocator { + static const char* name() { return "Cuda Unmanaged Allocator"; } - static void deallocate(void * /*ptr*/, size_t /*size*/) {} + static void deallocate(void* /*ptr*/, size_t /*size*/) {} static bool support_texture_binding() { return true; } }; /// class CudaUnmanagedAllocator /// does nothing when deallocate(ptr,size) is called -struct CudaUnmanagedUVMAllocator -{ - static const char * name() - { - return "Cuda Unmanaged UVM Allocator"; - } +struct CudaUnmanagedUVMAllocator { + static const char* name() { return "Cuda Unmanaged UVM Allocator"; } - static void deallocate(void * /*ptr*/, size_t /*size*/) {} + static void deallocate(void* /*ptr*/, size_t /*size*/) {} static bool support_texture_binding() { return true; } }; /// class CudaUnmanagedHostAllocator /// does nothing when deallocate(ptr,size) is called -class CudaUnmanagedHostAllocator -{ -public: - static const char * name() - { - return "Cuda Unmanaged Host Allocator"; - } +class CudaUnmanagedHostAllocator { + public: + static const char* name() { return "Cuda Unmanaged Host Allocator"; } // Unmanaged deallocate does nothing - static void deallocate(void * /*ptr*/, size_t /*size*/) {} + static void deallocate(void* /*ptr*/, size_t /*size*/) {} }; /// class CudaMallocAllocator -class CudaMallocAllocator -{ -public: - static const char * name() - { - return "Cuda Malloc Allocator"; - } +class CudaMallocAllocator { + public: + static const char* name() { return "Cuda Malloc Allocator"; } static void* allocate(size_t size); - static void deallocate(void * ptr, size_t); + static void deallocate(void* ptr, size_t); - static void * reallocate(void * old_ptr, size_t old_size, size_t new_size); + static void* reallocate(void* old_ptr, size_t old_size, size_t new_size); static bool support_texture_binding() { return true; } }; /// class CudaUVMAllocator -class CudaUVMAllocator -{ -public: - static const char * name() - { - return "Cuda UVM Allocator"; - } +class CudaUVMAllocator { + public: + static const char* name() { return "Cuda UVM Allocator"; } static void* allocate(size_t size); - static void deallocate(void * ptr, size_t); + static void deallocate(void* ptr, size_t); - static void * reallocate(void * old_ptr, size_t old_size, size_t new_size); + static void* reallocate(void* old_ptr, size_t old_size, size_t new_size); static bool support_texture_binding() { return true; } }; /// class CudaHostAllocator -class CudaHostAllocator -{ -public: - static const char * name() - { - return "Cuda Host Allocator"; - } +class CudaHostAllocator { + public: + static const char* name() { return "Cuda Host Allocator"; } static void* allocate(size_t size); - static void deallocate(void * ptr, size_t); + static void deallocate(void* ptr, size_t); - static void * reallocate(void * old_ptr, size_t old_size, size_t new_size); + static void* reallocate(void* old_ptr, size_t old_size, size_t new_size); }; +} // namespace Impl +} // namespace Kokkos -}} // namespace Kokkos::Impl - -#endif //KOKKOS_ENABLE_CUDA - -#endif // #ifndef KOKKOS_CUDA_ALLOCATION_TRACKING_HPP +#endif // KOKKOS_ENABLE_CUDA +#endif // #ifndef KOKKOS_CUDA_ALLOCATION_TRACKING_HPP diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp index 9d4bcbc8cf..8a6c0433c8 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics.hpp @@ -32,10 +32,10 @@ LICENSE ASSOCIATED WITH SUBSEQUENT MODIFICATIONS // ************************************************************************ // -// Kokkos v. 2.0 +// Kokkos v. 3.0 // Copyright (2019) Sandia Corporation // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -53,10 +53,10 @@ LICENSE ASSOCIATED WITH SUBSEQUENT MODIFICATIONS // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -82,85 +82,334 @@ LICENSE ASSOCIATED WITH SUBSEQUENT MODIFICATIONS namespace Kokkos { namespace Impl { - #ifndef __simt_scope // Modification: Kokkos GPU atomics should default to `gpu` scope #define __simt_scope "gpu" #endif -#define __simt_fence_signal_() asm volatile("":::"memory") -#define __simt_fence_sc_() asm volatile("fence.sc." __simt_scope ";":::"memory") -#define __simt_fence_() asm volatile("fence." __simt_scope ";":::"memory") - -#define __simt_load_acquire_8_as_32(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b8 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_8_as_32(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b8 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_8_as_32(ptr,desired) asm volatile("st.release." __simt_scope ".b8 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") -#define __simt_store_relaxed_8_as_32(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b8 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") - -#define __simt_load_acquire_16(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b16 %0, [%1];" : "=h"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_16(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b16 %0, [%1];" : "=h"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_16(ptr,desired) asm volatile("st.release." __simt_scope ".b16 [%0], %1;" :: "l"(ptr), "h"(desired) : "memory") -#define __simt_store_relaxed_16(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b16 [%0], %1;" :: "l"(ptr), "h"(desired) : "memory") - -#define __simt_load_acquire_32(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b32 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_32(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b32 %0, [%1];" : "=r"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_32(ptr,desired) asm volatile("st.release." __simt_scope ".b32 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") -#define __simt_store_relaxed_32(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b32 [%0], %1;" :: "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_release_32(ptr,old,desired) asm volatile("atom.exch.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_acquire_32(ptr,old,desired) asm volatile("atom.exch.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_acq_rel_32(ptr,old,desired) asm volatile("atom.exch.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_exch_relaxed_32(ptr,old,desired) asm volatile("atom.exch.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(desired) : "memory") -#define __simt_cas_release_32(ptr,old,expected,desired) asm volatile("atom.cas.release." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_cas_acquire_32(ptr,old,expected,desired) asm volatile("atom.cas.acquire." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_cas_acq_rel_32(ptr,old,expected,desired) asm volatile("atom.cas.acq_rel." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_cas_relaxed_32(ptr,old,expected,desired) asm volatile("atom.cas.relaxed." __simt_scope ".b32 %0, [%1], %2, %3;" : "=r"(old) : "l"(ptr), "r"(expected), "r"(desired) : "memory") -#define __simt_add_release_32(ptr,old,addend) asm volatile("atom.add.release." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_add_acquire_32(ptr,old,addend) asm volatile("atom.add.acquire." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_add_acq_rel_32(ptr,old,addend) asm volatile("atom.add.acq_rel." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_add_relaxed_32(ptr,old,addend) asm volatile("atom.add.relaxed." __simt_scope ".u32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(addend) : "memory") -#define __simt_and_release_32(ptr,old,andend) asm volatile("atom.and.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_and_acquire_32(ptr,old,andend) asm volatile("atom.and.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_and_acq_rel_32(ptr,old,andend) asm volatile("atom.and.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_and_relaxed_32(ptr,old,andend) asm volatile("atom.and.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(andend) : "memory") -#define __simt_or_release_32(ptr,old,orend) asm volatile("atom.or.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_or_acquire_32(ptr,old,orend) asm volatile("atom.or.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_or_acq_rel_32(ptr,old,orend) asm volatile("atom.or.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_or_relaxed_32(ptr,old,orend) asm volatile("atom.or.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(orend) : "memory") -#define __simt_xor_release_32(ptr,old,xorend) asm volatile("atom.xor.release." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") -#define __simt_xor_acquire_32(ptr,old,xorend) asm volatile("atom.xor.acquire." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") -#define __simt_xor_acq_rel_32(ptr,old,xorend) asm volatile("atom.xor.acq_rel." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") -#define __simt_xor_relaxed_32(ptr,old,xorend) asm volatile("atom.xor.relaxed." __simt_scope ".b32 %0, [%1], %2;" : "=r"(old) : "l"(ptr), "r"(xorend) : "memory") - -#define __simt_load_acquire_64(ptr,ret) asm volatile("ld.acquire." __simt_scope ".b64 %0, [%1];" : "=l"(ret) : "l"(ptr) : "memory") -#define __simt_load_relaxed_64(ptr,ret) asm volatile("ld.relaxed." __simt_scope ".b64 %0, [%1];" : "=l"(ret) : "l"(ptr) : "memory") -#define __simt_store_release_64(ptr,desired) asm volatile("st.release." __simt_scope ".b64 [%0], %1;" :: "l"(ptr), "l"(desired) : "memory") -#define __simt_store_relaxed_64(ptr,desired) asm volatile("st.relaxed." __simt_scope ".b64 [%0], %1;" :: "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_release_64(ptr,old,desired) asm volatile("atom.exch.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_acquire_64(ptr,old,desired) asm volatile("atom.exch.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_acq_rel_64(ptr,old,desired) asm volatile("atom.exch.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_exch_relaxed_64(ptr,old,desired) asm volatile("atom.exch.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(desired) : "memory") -#define __simt_cas_release_64(ptr,old,expected,desired) asm volatile("atom.cas.release." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_cas_acquire_64(ptr,old,expected,desired) asm volatile("atom.cas.acquire." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_cas_acq_rel_64(ptr,old,expected,desired) asm volatile("atom.cas.acq_rel." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_cas_relaxed_64(ptr,old,expected,desired) asm volatile("atom.cas.relaxed." __simt_scope ".b64 %0, [%1], %2, %3;" : "=l"(old) : "l"(ptr), "l"(expected), "l"(desired) : "memory") -#define __simt_add_release_64(ptr,old,addend) asm volatile("atom.add.release." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_add_acquire_64(ptr,old,addend) asm volatile("atom.add.acquire." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_add_acq_rel_64(ptr,old,addend) asm volatile("atom.add.acq_rel." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_add_relaxed_64(ptr,old,addend) asm volatile("atom.add.relaxed." __simt_scope ".u64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(addend) : "memory") -#define __simt_and_release_64(ptr,old,andend) asm volatile("atom.and.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_and_acquire_64(ptr,old,andend) asm volatile("atom.and.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_and_acq_rel_64(ptr,old,andend) asm volatile("atom.and.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_and_relaxed_64(ptr,old,andend) asm volatile("atom.and.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(andend) : "memory") -#define __simt_or_release_64(ptr,old,orend) asm volatile("atom.or.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_or_acquire_64(ptr,old,orend) asm volatile("atom.or.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_or_acq_rel_64(ptr,old,orend) asm volatile("atom.or.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_or_relaxed_64(ptr,old,orend) asm volatile("atom.or.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(orend) : "memory") -#define __simt_xor_release_64(ptr,old,xorend) asm volatile("atom.xor.release." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") -#define __simt_xor_acquire_64(ptr,old,xorend) asm volatile("atom.xor.acquire." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") -#define __simt_xor_acq_rel_64(ptr,old,xorend) asm volatile("atom.xor.acq_rel." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") -#define __simt_xor_relaxed_64(ptr,old,xorend) asm volatile("atom.xor.relaxed." __simt_scope ".b64 %0, [%1], %2;" : "=l"(old) : "l"(ptr), "l"(xorend) : "memory") - -#define __simt_nanosleep(timeout) asm volatile("nanosleep.u32 %0;" :: "r"(unsigned(timeout)) : ) +#define __simt_fence_signal_() asm volatile("" ::: "memory") +#define __simt_fence_sc_() \ + asm volatile("fence.sc." __simt_scope ";" ::: "memory") +#define __simt_fence_() asm volatile("fence." __simt_scope ";" ::: "memory") + +#define __simt_load_acquire_8_as_32(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b8 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_8_as_32(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b8 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_8_as_32(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b8 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") +#define __simt_store_relaxed_8_as_32(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b8 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") + +#define __simt_load_acquire_16(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b16 %0, [%1];" \ + : "=h"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_16(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b16 %0, [%1];" \ + : "=h"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_16(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b16 [%0], %1;" ::"l"(ptr), \ + "h"(desired) \ + : "memory") +#define __simt_store_relaxed_16(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b16 [%0], %1;" ::"l"(ptr), \ + "h"(desired) \ + : "memory") + +#define __simt_load_acquire_32(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b32 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_32(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b32 %0, [%1];" \ + : "=r"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_32(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b32 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") +#define __simt_store_relaxed_32(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b32 [%0], %1;" ::"l"(ptr), \ + "r"(desired) \ + : "memory") +#define __simt_exch_release_32(ptr, old, desired) \ + asm volatile("atom.exch.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_exch_acquire_32(ptr, old, desired) \ + asm volatile("atom.exch.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_exch_acq_rel_32(ptr, old, desired) \ + asm volatile("atom.exch.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_exch_relaxed_32(ptr, old, desired) \ + asm volatile("atom.exch.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(desired) \ + : "memory") +#define __simt_cas_release_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.release." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_cas_acquire_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.acquire." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_cas_acq_rel_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.acq_rel." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_cas_relaxed_32(ptr, old, expected, desired) \ + asm volatile("atom.cas.relaxed." __simt_scope ".b32 %0, [%1], %2, %3;" \ + : "=r"(old) \ + : "l"(ptr), "r"(expected), "r"(desired) \ + : "memory") +#define __simt_add_release_32(ptr, old, addend) \ + asm volatile("atom.add.release." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_add_acquire_32(ptr, old, addend) \ + asm volatile("atom.add.acquire." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_add_acq_rel_32(ptr, old, addend) \ + asm volatile("atom.add.acq_rel." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_add_relaxed_32(ptr, old, addend) \ + asm volatile("atom.add.relaxed." __simt_scope ".u32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(addend) \ + : "memory") +#define __simt_and_release_32(ptr, old, andend) \ + asm volatile("atom.and.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_and_acquire_32(ptr, old, andend) \ + asm volatile("atom.and.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_and_acq_rel_32(ptr, old, andend) \ + asm volatile("atom.and.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_and_relaxed_32(ptr, old, andend) \ + asm volatile("atom.and.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(andend) \ + : "memory") +#define __simt_or_release_32(ptr, old, orend) \ + asm volatile("atom.or.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_or_acquire_32(ptr, old, orend) \ + asm volatile("atom.or.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_or_acq_rel_32(ptr, old, orend) \ + asm volatile("atom.or.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_or_relaxed_32(ptr, old, orend) \ + asm volatile("atom.or.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(orend) \ + : "memory") +#define __simt_xor_release_32(ptr, old, xorend) \ + asm volatile("atom.xor.release." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") +#define __simt_xor_acquire_32(ptr, old, xorend) \ + asm volatile("atom.xor.acquire." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") +#define __simt_xor_acq_rel_32(ptr, old, xorend) \ + asm volatile("atom.xor.acq_rel." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") +#define __simt_xor_relaxed_32(ptr, old, xorend) \ + asm volatile("atom.xor.relaxed." __simt_scope ".b32 %0, [%1], %2;" \ + : "=r"(old) \ + : "l"(ptr), "r"(xorend) \ + : "memory") + +#define __simt_load_acquire_64(ptr, ret) \ + asm volatile("ld.acquire." __simt_scope ".b64 %0, [%1];" \ + : "=l"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_load_relaxed_64(ptr, ret) \ + asm volatile("ld.relaxed." __simt_scope ".b64 %0, [%1];" \ + : "=l"(ret) \ + : "l"(ptr) \ + : "memory") +#define __simt_store_release_64(ptr, desired) \ + asm volatile("st.release." __simt_scope ".b64 [%0], %1;" ::"l"(ptr), \ + "l"(desired) \ + : "memory") +#define __simt_store_relaxed_64(ptr, desired) \ + asm volatile("st.relaxed." __simt_scope ".b64 [%0], %1;" ::"l"(ptr), \ + "l"(desired) \ + : "memory") +#define __simt_exch_release_64(ptr, old, desired) \ + asm volatile("atom.exch.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_exch_acquire_64(ptr, old, desired) \ + asm volatile("atom.exch.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_exch_acq_rel_64(ptr, old, desired) \ + asm volatile("atom.exch.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_exch_relaxed_64(ptr, old, desired) \ + asm volatile("atom.exch.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(desired) \ + : "memory") +#define __simt_cas_release_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.release." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_cas_acquire_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.acquire." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_cas_acq_rel_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.acq_rel." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_cas_relaxed_64(ptr, old, expected, desired) \ + asm volatile("atom.cas.relaxed." __simt_scope ".b64 %0, [%1], %2, %3;" \ + : "=l"(old) \ + : "l"(ptr), "l"(expected), "l"(desired) \ + : "memory") +#define __simt_add_release_64(ptr, old, addend) \ + asm volatile("atom.add.release." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_add_acquire_64(ptr, old, addend) \ + asm volatile("atom.add.acquire." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_add_acq_rel_64(ptr, old, addend) \ + asm volatile("atom.add.acq_rel." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_add_relaxed_64(ptr, old, addend) \ + asm volatile("atom.add.relaxed." __simt_scope ".u64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(addend) \ + : "memory") +#define __simt_and_release_64(ptr, old, andend) \ + asm volatile("atom.and.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_and_acquire_64(ptr, old, andend) \ + asm volatile("atom.and.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_and_acq_rel_64(ptr, old, andend) \ + asm volatile("atom.and.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_and_relaxed_64(ptr, old, andend) \ + asm volatile("atom.and.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(andend) \ + : "memory") +#define __simt_or_release_64(ptr, old, orend) \ + asm volatile("atom.or.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_or_acquire_64(ptr, old, orend) \ + asm volatile("atom.or.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_or_acq_rel_64(ptr, old, orend) \ + asm volatile("atom.or.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_or_relaxed_64(ptr, old, orend) \ + asm volatile("atom.or.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(orend) \ + : "memory") +#define __simt_xor_release_64(ptr, old, xorend) \ + asm volatile("atom.xor.release." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") +#define __simt_xor_acquire_64(ptr, old, xorend) \ + asm volatile("atom.xor.acquire." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") +#define __simt_xor_acq_rel_64(ptr, old, xorend) \ + asm volatile("atom.xor.acq_rel." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") +#define __simt_xor_relaxed_64(ptr, old, xorend) \ + asm volatile("atom.xor.relaxed." __simt_scope ".b64 %0, [%1], %2;" \ + : "=l"(old) \ + : "l"(ptr), "l"(xorend) \ + : "memory") + +#define __simt_nanosleep(timeout) \ + asm volatile("nanosleep.u32 %0;" ::"r"(unsigned(timeout)) :) /* definitions @@ -189,309 +438,355 @@ namespace Impl { #endif inline __device__ int __stronger_order_simt_(int a, int b) { - if (b == __ATOMIC_SEQ_CST) return __ATOMIC_SEQ_CST; - if (b == __ATOMIC_RELAXED) return a; - switch (a) { + if (b == __ATOMIC_SEQ_CST) return __ATOMIC_SEQ_CST; + if (b == __ATOMIC_RELAXED) return a; + switch (a) { case __ATOMIC_SEQ_CST: case __ATOMIC_ACQ_REL: return a; case __ATOMIC_CONSUME: - case __ATOMIC_ACQUIRE: if (b != __ATOMIC_ACQUIRE) return __ATOMIC_ACQ_REL; else return __ATOMIC_ACQUIRE; - case __ATOMIC_RELEASE: if (b != __ATOMIC_RELEASE) return __ATOMIC_ACQ_REL; else return __ATOMIC_RELEASE; + case __ATOMIC_ACQUIRE: + if (b != __ATOMIC_ACQUIRE) + return __ATOMIC_ACQ_REL; + else + return __ATOMIC_ACQUIRE; + case __ATOMIC_RELEASE: + if (b != __ATOMIC_RELEASE) + return __ATOMIC_ACQ_REL; + else + return __ATOMIC_RELEASE; case __ATOMIC_RELAXED: return b; default: assert(0); - } - return __ATOMIC_SEQ_CST; + } + return __ATOMIC_SEQ_CST; } /* base */ -#define DO__atomic_load_simt_(bytes, bits) \ -template::type = 0> \ -void __device__ __atomic_load_simt_ (const type *ptr, type *ret, int memorder) { \ - int##bits##_t tmp = 0; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_load_acquire_##bits(ptr, tmp); break; \ - case __ATOMIC_RELAXED: __simt_load_relaxed_##bits(ptr, tmp); break; \ - default: assert(0); \ - } \ - memcpy(ret, &tmp, bytes); \ -} -DO__atomic_load_simt_(1,32) -DO__atomic_load_simt_(2,16) -DO__atomic_load_simt_(4,32) -DO__atomic_load_simt_(8,64) - -template -type __device__ __atomic_load_n_simt_(const type *ptr, int memorder) { - type ret; - __atomic_load_simt_(ptr, &ret, memorder); - return ret; -} - -#define DO__atomic_store_simt_(bytes, bits) \ -template::type = 0> \ -void __device__ __atomic_store_simt_ (type *ptr, type *val, int memorder) { \ - int##bits##_t tmp = 0; \ - memcpy(&tmp, val, bytes); \ - switch (memorder) { \ - case __ATOMIC_RELEASE: __simt_store_release_##bits(ptr, tmp); break; \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_RELAXED: __simt_store_relaxed_##bits(ptr, tmp); break; \ - default: assert(0); \ - } \ -} -DO__atomic_store_simt_(1,32) -DO__atomic_store_simt_(2,16) -DO__atomic_store_simt_(4,32) -DO__atomic_store_simt_(8,64) - -template -void __device__ __atomic_store_n_simt_(type *ptr, type val, int memorder) { - __atomic_store_simt_(ptr, &val, memorder); -} - -#define DO__atomic_compare_exchange_simt_(bytes, bits) \ -template::type = 0> \ -bool __device__ __atomic_compare_exchange_simt_ (type *ptr, type *expected, const type *desired, bool, int success_memorder, int failure_memorder) { \ - int##bits##_t tmp = 0, old = 0, old_tmp; \ - memcpy(&tmp, desired, bytes); \ - memcpy(&old, expected, bytes); \ - old_tmp = old; \ - switch (__stronger_order_simt_(success_memorder, failure_memorder)) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_cas_acquire_##bits(ptr, old, old_tmp, tmp); break; \ - case __ATOMIC_ACQ_REL: __simt_cas_acq_rel_##bits(ptr, old, old_tmp, tmp); break; \ - case __ATOMIC_RELEASE: __simt_cas_release_##bits(ptr, old, old_tmp, tmp); break; \ - case __ATOMIC_RELAXED: __simt_cas_relaxed_##bits(ptr, old, old_tmp, tmp); break; \ - default: assert(0); \ - } \ - bool const ret = old == old_tmp; \ - memcpy(expected, &old, bytes); \ - return ret; \ -} +#define DO__atomic_load_simt_(bytes, bits) \ + template ::type = 0> \ + void __device__ __atomic_load_simt_(const type *ptr, type *ret, \ + int memorder) { \ + int##bits##_t tmp = 0; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_load_acquire_##bits(ptr, tmp); break; \ + case __ATOMIC_RELAXED: __simt_load_relaxed_##bits(ptr, tmp); break; \ + default: assert(0); \ + } \ + memcpy(ret, &tmp, bytes); \ + } +DO__atomic_load_simt_(1, 32) DO__atomic_load_simt_(2, 16) + DO__atomic_load_simt_(4, 32) DO__atomic_load_simt_(8, 64) + + template + type __device__ __atomic_load_n_simt_(const type *ptr, int memorder) { + type ret; + __atomic_load_simt_(ptr, &ret, memorder); + return ret; +} + +#define DO__atomic_store_simt_(bytes, bits) \ + template ::type = 0> \ + void __device__ __atomic_store_simt_(type *ptr, type *val, int memorder) { \ + int##bits##_t tmp = 0; \ + memcpy(&tmp, val, bytes); \ + switch (memorder) { \ + case __ATOMIC_RELEASE: __simt_store_release_##bits(ptr, tmp); break; \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_RELAXED: __simt_store_relaxed_##bits(ptr, tmp); break; \ + default: assert(0); \ + } \ + } +DO__atomic_store_simt_(1, 32) DO__atomic_store_simt_(2, 16) + DO__atomic_store_simt_(4, 32) DO__atomic_store_simt_(8, 64) + + template + void __device__ + __atomic_store_n_simt_(type *ptr, type val, int memorder) { + __atomic_store_simt_(ptr, &val, memorder); +} + +#define DO__atomic_compare_exchange_simt_(bytes, bits) \ + template ::type = 0> \ + bool __device__ __atomic_compare_exchange_simt_( \ + type *ptr, type *expected, const type *desired, bool, \ + int success_memorder, int failure_memorder) { \ + int##bits##_t tmp = 0, old = 0, old_tmp; \ + memcpy(&tmp, desired, bytes); \ + memcpy(&old, expected, bytes); \ + old_tmp = old; \ + switch (__stronger_order_simt_(success_memorder, failure_memorder)) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: \ + __simt_cas_acquire_##bits(ptr, old, old_tmp, tmp); \ + break; \ + case __ATOMIC_ACQ_REL: \ + __simt_cas_acq_rel_##bits(ptr, old, old_tmp, tmp); \ + break; \ + case __ATOMIC_RELEASE: \ + __simt_cas_release_##bits(ptr, old, old_tmp, tmp); \ + break; \ + case __ATOMIC_RELAXED: \ + __simt_cas_relaxed_##bits(ptr, old, old_tmp, tmp); \ + break; \ + default: assert(0); \ + } \ + bool const ret = old == old_tmp; \ + memcpy(expected, &old, bytes); \ + return ret; \ + } DO__atomic_compare_exchange_simt_(4, 32) -DO__atomic_compare_exchange_simt_(8, 64) - -template::type = 0> \ -bool __device__ __atomic_compare_exchange_simt_(type *ptr, type *expected, const type *desired, bool, int success_memorder, int failure_memorder) { - - using R = typename std::conditional::value, volatile uint32_t, uint32_t>::type; - auto const aligned = (R*)((intptr_t)ptr & ~(sizeof(uint32_t) - 1)); - auto const offset = uint32_t((intptr_t)ptr & (sizeof(uint32_t) - 1)) * 8; - auto const mask = ((1 << sizeof(type)*8) - 1) << offset; - - uint32_t old = *expected << offset, old_value; - while (1) { - old_value = (old & mask) >> offset; - if (old_value != *expected) - break; - uint32_t const attempt = (old & ~mask) | (*desired << offset); - if (__atomic_compare_exchange_simt_ (aligned, &old, &attempt, true, success_memorder, failure_memorder)) - return true; - } - *expected = old_value; - return false; -} - -template -bool __device__ __atomic_compare_exchange_n_simt_(type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_simt_(ptr, expected, &desired, weak, success_memorder, failure_memorder); -} - -#define DO__atomic_exchange_simt_(bytes, bits) \ -template::type = 0> \ -void __device__ __atomic_exchange_simt_ (type *ptr, type *val, type *ret, int memorder) { \ - int##bits##_t tmp = 0; \ - memcpy(&tmp, val, bytes); \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_exch_acquire_##bits(ptr, tmp, tmp); break; \ - case __ATOMIC_ACQ_REL: __simt_exch_acq_rel_##bits(ptr, tmp, tmp); break; \ - case __ATOMIC_RELEASE: __simt_exch_release_##bits(ptr, tmp, tmp); break; \ - case __ATOMIC_RELAXED: __simt_exch_relaxed_##bits(ptr, tmp, tmp); break; \ - default: assert(0); \ - } \ - memcpy(ret, &tmp, bytes); \ -} -DO__atomic_exchange_simt_(4,32) -DO__atomic_exchange_simt_(8,64) - -template::type = 0> -void __device__ __atomic_exchange_simt_ (type *ptr, type *val, type *ret, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - while(!__atomic_compare_exchange_simt_(ptr, &expected, val, true, memorder, memorder)) - ; - *ret = expected; -} - -template + DO__atomic_compare_exchange_simt_(8, 64) + + template ::type = 0> + bool __device__ + __atomic_compare_exchange_simt_(type *ptr, type *expected, + const type *desired, bool, + int success_memorder, + int failure_memorder) { + using R = typename std::conditional::value, + volatile uint32_t, uint32_t>::type; + auto const aligned = (R *)((intptr_t)ptr & ~(sizeof(uint32_t) - 1)); + auto const offset = uint32_t((intptr_t)ptr & (sizeof(uint32_t) - 1)) * 8; + auto const mask = ((1 << sizeof(type) * 8) - 1) << offset; + + uint32_t old = *expected << offset, old_value; + while (1) { + old_value = (old & mask) >> offset; + if (old_value != *expected) break; + uint32_t const attempt = (old & ~mask) | (*desired << offset); + if (__atomic_compare_exchange_simt_(aligned, &old, &attempt, true, + success_memorder, failure_memorder)) + return true; + } + *expected = old_value; + return false; +} + +template +bool __device__ __atomic_compare_exchange_n_simt_(type *ptr, type *expected, + type desired, bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_simt_(ptr, expected, &desired, weak, + success_memorder, failure_memorder); +} + +#define DO__atomic_exchange_simt_(bytes, bits) \ + template ::type = 0> \ + void __device__ __atomic_exchange_simt_(type *ptr, type *val, type *ret, \ + int memorder) { \ + int##bits##_t tmp = 0; \ + memcpy(&tmp, val, bytes); \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_exch_acquire_##bits(ptr, tmp, tmp); break; \ + case __ATOMIC_ACQ_REL: __simt_exch_acq_rel_##bits(ptr, tmp, tmp); break; \ + case __ATOMIC_RELEASE: __simt_exch_release_##bits(ptr, tmp, tmp); break; \ + case __ATOMIC_RELAXED: __simt_exch_relaxed_##bits(ptr, tmp, tmp); break; \ + default: assert(0); \ + } \ + memcpy(ret, &tmp, bytes); \ + } +DO__atomic_exchange_simt_(4, 32) DO__atomic_exchange_simt_(8, 64) + + template ::type = 0> + void __device__ + __atomic_exchange_simt_(type *ptr, type *val, type *ret, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + while (!__atomic_compare_exchange_simt_(ptr, &expected, val, true, memorder, + memorder)) + ; + *ret = expected; +} + +template type __device__ __atomic_exchange_n_simt_(type *ptr, type val, int memorder) { - type ret; - __atomic_exchange_simt_(ptr, &val, &ret, memorder); - return ret; -} - -#define DO__atomic_fetch_add_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_add_simt_ (type *ptr, delta val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_add_simt_(4, 32) -DO__atomic_fetch_add_simt_(8, 64) - -template::type = 0> -type __device__ __atomic_fetch_add_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected + val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_sub_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_sub_simt_ (type *ptr, delta val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, -val); break; \ - case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, -val); break; \ - case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, -val); break; \ - case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, -val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_sub_simt_(4,32) -DO__atomic_fetch_sub_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_sub_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected - val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_and_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_and_simt_ (type *ptr, type val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_and_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_and_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_and_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_and_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_and_simt_(4,32) -DO__atomic_fetch_and_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_and_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected & val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_xor_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_xor_simt_ (type *ptr, type val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_xor_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_xor_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_xor_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_xor_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_xor_simt_(4,32) -DO__atomic_fetch_xor_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_xor_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected ^ val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -#define DO__atomic_fetch_or_simt_(bytes, bits) \ -template::type = 0> \ -type __device__ __atomic_fetch_or_simt_ (type *ptr, type val, int memorder) { \ - type ret; \ - switch (memorder) { \ - case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ - case __ATOMIC_CONSUME: \ - case __ATOMIC_ACQUIRE: __simt_or_acquire_##bits(ptr, ret, val); break; \ - case __ATOMIC_ACQ_REL: __simt_or_acq_rel_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELEASE: __simt_or_release_##bits(ptr, ret, val); break; \ - case __ATOMIC_RELAXED: __simt_or_relaxed_##bits(ptr, ret, val); break; \ - default: assert(0); \ - } \ - return ret; \ -} -DO__atomic_fetch_or_simt_(4,32) -DO__atomic_fetch_or_simt_(8,64) - -template::type = 0> -type __device__ __atomic_fetch_or_simt_ (type *ptr, delta val, int memorder) { - - type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); - type const desired = expected | val; - while(!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, memorder, memorder)) - ; - return expected; -} - -template + type ret; + __atomic_exchange_simt_(ptr, &val, &ret, memorder); + return ret; +} + +#define DO__atomic_fetch_add_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_add_simt_(type *ptr, delta val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_add_simt_(4, 32) DO__atomic_fetch_add_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_add_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected + val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_sub_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_sub_simt_(type *ptr, delta val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_add_acquire_##bits(ptr, ret, -val); break; \ + case __ATOMIC_ACQ_REL: __simt_add_acq_rel_##bits(ptr, ret, -val); break; \ + case __ATOMIC_RELEASE: __simt_add_release_##bits(ptr, ret, -val); break; \ + case __ATOMIC_RELAXED: __simt_add_relaxed_##bits(ptr, ret, -val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_sub_simt_(4, 32) DO__atomic_fetch_sub_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_sub_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected - val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_and_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_and_simt_(type *ptr, type val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_and_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_and_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_and_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_and_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_and_simt_(4, 32) DO__atomic_fetch_and_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_and_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected & val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_xor_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_xor_simt_(type *ptr, type val, \ + int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_xor_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_xor_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_xor_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_xor_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_xor_simt_(4, 32) DO__atomic_fetch_xor_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_xor_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected ^ val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +#define DO__atomic_fetch_or_simt_(bytes, bits) \ + template ::type = 0> \ + type __device__ __atomic_fetch_or_simt_(type *ptr, type val, int memorder) { \ + type ret; \ + switch (memorder) { \ + case __ATOMIC_SEQ_CST: __simt_fence_sc_(); \ + case __ATOMIC_CONSUME: \ + case __ATOMIC_ACQUIRE: __simt_or_acquire_##bits(ptr, ret, val); break; \ + case __ATOMIC_ACQ_REL: __simt_or_acq_rel_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELEASE: __simt_or_release_##bits(ptr, ret, val); break; \ + case __ATOMIC_RELAXED: __simt_or_relaxed_##bits(ptr, ret, val); break; \ + default: assert(0); \ + } \ + return ret; \ + } +DO__atomic_fetch_or_simt_(4, 32) DO__atomic_fetch_or_simt_(8, 64) + + template ::type = 0> + type __device__ + __atomic_fetch_or_simt_(type *ptr, delta val, int memorder) { + type expected = __atomic_load_n_simt_(ptr, __ATOMIC_RELAXED); + type const desired = expected | val; + while (!__atomic_compare_exchange_simt_(ptr, &expected, &desired, true, + memorder, memorder)) + ; + return expected; +} + +template inline bool __device__ __atomic_test_and_set_simt_(type *ptr, int memorder) { - return __atomic_exchange_n_simt_((char*)ptr, (char)1, memorder) == 1; + return __atomic_exchange_n_simt_((char *)ptr, (char)1, memorder) == 1; } -template +template inline void __device__ __atomic_clear_simt_(type *ptr, int memorder) { - return __atomic_store_n_simt_((char*)ptr, (char)0, memorder); + return __atomic_store_n_simt_((char *)ptr, (char)0, memorder); } -inline constexpr __device__ bool __atomic_always_lock_free_simt_ (size_t size, void *) { - return size <= 8; +inline constexpr __device__ bool __atomic_always_lock_free_simt_(size_t size, + void *) { + return size <= 8; } -inline __device__ bool __atomic_is_lock_free_simt_(size_t size, void * ptr) { - return __atomic_always_lock_free_simt_(size, ptr); +inline __device__ bool __atomic_is_lock_free_simt_(size_t size, void *ptr) { + return __atomic_always_lock_free_simt_(size, ptr); } /* @@ -499,7 +794,7 @@ inline __device__ bool __atomic_is_lock_free_simt_(size_t size, void * ptr) { */ inline void __device__ __atomic_thread_fence_simt(int memorder) { - switch (memorder) { + switch (memorder) { case __ATOMIC_SEQ_CST: __simt_fence_sc_(); break; case __ATOMIC_CONSUME: case __ATOMIC_ACQUIRE: @@ -507,124 +802,184 @@ inline void __device__ __atomic_thread_fence_simt(int memorder) { case __ATOMIC_RELEASE: __simt_fence_(); break; case __ATOMIC_RELAXED: break; default: assert(0); - } + } } -inline void __device__ __atomic_signal_fence_simt(int memorder) { - __atomic_thread_fence_simt(memorder); +inline void __device__ __atomic_signal_fence_simt(int memorder) { + __atomic_thread_fence_simt(memorder); } /* non-volatile */ -template type __device__ __atomic_load_n_simt(const type *ptr, int memorder) { - return __atomic_load_n_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_load_simt(const type *ptr, type *ret, int memorder) { - __atomic_load_simt_(const_cast(ptr), ret, memorder); -} -template void __device__ __atomic_store_n_simt(type *ptr, type val, int memorder) { - __atomic_store_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_store_simt(type *ptr, type *val, int memorder) { - __atomic_store_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_exchange_n_simt(type *ptr, type val, int memorder) { - return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_exchange_simt(type *ptr, type *val, type *ret, int memorder) { - __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); -} -template bool __device__ __atomic_compare_exchange_n_simt(type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template bool __device__ __atomic_compare_exchange_simt(type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template type __device__ __atomic_fetch_add_simt(type *ptr, delta val, int memorder) { - return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_sub_simt(type *ptr, delta val, int memorder) { - return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_and_simt(type *ptr, type val, int memorder) { - return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_xor_simt(type *ptr, type val, int memorder) { - return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_or_simt(type *ptr, type val, int memorder) { - return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); -} -template bool __device__ __atomic_test_and_set_simt(void *ptr, int memorder) { - return __atomic_test_and_set_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_clear_simt(void *ptr, int memorder) { - return __atomic_clear_simt_(const_cast(ptr), memorder); +template +type __device__ __atomic_load_n_simt(const type *ptr, int memorder) { + return __atomic_load_n_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_load_simt(const type *ptr, type *ret, int memorder) { + __atomic_load_simt_(const_cast(ptr), ret, memorder); +} +template +void __device__ __atomic_store_n_simt(type *ptr, type val, int memorder) { + __atomic_store_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_store_simt(type *ptr, type *val, int memorder) { + __atomic_store_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_exchange_n_simt(type *ptr, type val, int memorder) { + return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_exchange_simt(type *ptr, type *val, type *ret, + int memorder) { + __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); +} +template +bool __device__ __atomic_compare_exchange_n_simt(type *ptr, type *expected, + type desired, bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +bool __device__ __atomic_compare_exchange_simt(type *ptr, type *expected, + type *desired, bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +type __device__ __atomic_fetch_add_simt(type *ptr, delta val, int memorder) { + return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_sub_simt(type *ptr, delta val, int memorder) { + return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_and_simt(type *ptr, type val, int memorder) { + return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_xor_simt(type *ptr, type val, int memorder) { + return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_or_simt(type *ptr, type val, int memorder) { + return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); +} +template +bool __device__ __atomic_test_and_set_simt(void *ptr, int memorder) { + return __atomic_test_and_set_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_clear_simt(void *ptr, int memorder) { + return __atomic_clear_simt_(const_cast(ptr), memorder); } inline bool __device__ __atomic_always_lock_free_simt(size_t size, void *ptr) { - return __atomic_always_lock_free_simt_(size, const_cast(ptr)); + return __atomic_always_lock_free_simt_(size, const_cast(ptr)); } inline bool __device__ __atomic_is_lock_free_simt(size_t size, void *ptr) { - return __atomic_is_lock_free_simt_(size, const_cast(ptr)); + return __atomic_is_lock_free_simt_(size, const_cast(ptr)); } /* - volatile + volatile */ -template type __device__ __atomic_load_n_simt(const volatile type *ptr, int memorder) { - return __atomic_load_n_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_load_simt(const volatile type *ptr, type *ret, int memorder) { - __atomic_load_simt_(const_cast(ptr), ret, memorder); -} -template void __device__ __atomic_store_n_simt(volatile type *ptr, type val, int memorder) { - __atomic_store_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_store_simt(volatile type *ptr, type *val, int memorder) { - __atomic_store_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_exchange_n_simt(volatile type *ptr, type val, int memorder) { - return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); -} -template void __device__ __atomic_exchange_simt(volatile type *ptr, type *val, type *ret, int memorder) { - __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); -} -template bool __device__ __atomic_compare_exchange_n_simt(volatile type *ptr, type *expected, type desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template bool __device__ __atomic_compare_exchange_simt(volatile type *ptr, type *expected, type *desired, bool weak, int success_memorder, int failure_memorder) { - return __atomic_compare_exchange_simt_(const_cast(ptr), expected, desired, weak, success_memorder, failure_memorder); -} -template type __device__ __atomic_fetch_add_simt(volatile type *ptr, delta val, int memorder) { - return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_sub_simt(volatile type *ptr, delta val, int memorder) { - return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_and_simt(volatile type *ptr, type val, int memorder) { - return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_xor_simt(volatile type *ptr, type val, int memorder) { - return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); -} -template type __device__ __atomic_fetch_or_simt(volatile type *ptr, type val, int memorder) { - return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); -} -template bool __device__ __atomic_test_and_set_simt(volatile void *ptr, int memorder) { - return __atomic_test_and_set_simt_(const_cast(ptr), memorder); -} -template void __device__ __atomic_clear_simt(volatile void *ptr, int memorder) { - return __atomic_clear_simt_(const_cast(ptr), memorder); -} - - - -} // end namespace Impl -} // end namespace Kokkos - -#endif //_SIMT_DETAILS_CONFIG +template +type __device__ __atomic_load_n_simt(const volatile type *ptr, int memorder) { + return __atomic_load_n_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_load_simt(const volatile type *ptr, type *ret, + int memorder) { + __atomic_load_simt_(const_cast(ptr), ret, memorder); +} +template +void __device__ __atomic_store_n_simt(volatile type *ptr, type val, + int memorder) { + __atomic_store_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_store_simt(volatile type *ptr, type *val, + int memorder) { + __atomic_store_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_exchange_n_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_exchange_n_simt_(const_cast(ptr), val, memorder); +} +template +void __device__ __atomic_exchange_simt(volatile type *ptr, type *val, type *ret, + int memorder) { + __atomic_exchange_simt_(const_cast(ptr), val, ret, memorder); +} +template +bool __device__ __atomic_compare_exchange_n_simt(volatile type *ptr, + type *expected, type desired, + bool weak, + int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_n_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +bool __device__ __atomic_compare_exchange_simt(volatile type *ptr, + type *expected, type *desired, + bool weak, int success_memorder, + int failure_memorder) { + return __atomic_compare_exchange_simt_(const_cast(ptr), expected, + desired, weak, success_memorder, + failure_memorder); +} +template +type __device__ __atomic_fetch_add_simt(volatile type *ptr, delta val, + int memorder) { + return __atomic_fetch_add_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_sub_simt(volatile type *ptr, delta val, + int memorder) { + return __atomic_fetch_sub_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_and_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_fetch_and_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_xor_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_fetch_xor_simt_(const_cast(ptr), val, memorder); +} +template +type __device__ __atomic_fetch_or_simt(volatile type *ptr, type val, + int memorder) { + return __atomic_fetch_or_simt_(const_cast(ptr), val, memorder); +} +template +bool __device__ __atomic_test_and_set_simt(volatile void *ptr, int memorder) { + return __atomic_test_and_set_simt_(const_cast(ptr), memorder); +} +template +void __device__ __atomic_clear_simt(volatile void *ptr, int memorder) { + return __atomic_clear_simt_(const_cast(ptr), memorder); +} + +} // end namespace Impl +} // end namespace Kokkos + +#endif //_SIMT_DETAILS_CONFIG #ifndef KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED /* @@ -653,5 +1008,5 @@ template void __device__ __atomic_clear_simt(volatile void *ptr, int #define KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED -#endif //__CUDA_ARCH__ && KOKKOS_ENABLE_CUDA_ASM_ATOMICS -#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED +#endif //__CUDA_ARCH__ && KOKKOS_ENABLE_CUDA_ASM_ATOMICS +#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp index bedb147227..d7cd1bab13 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Atomic_Intrinsics_Restore_Builtins.hpp @@ -2,10 +2,10 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 +// Kokkos v. 3.0 // Copyright (2019) Sandia Corporation // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -65,4 +65,4 @@ #undef KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED -#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED +#endif // KOKKOS_SIMT_ATOMIC_BUILTIN_REPLACEMENTS_DEFINED diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp index 932bde2b37..34b681be15 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_BlockSize_Deduction.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,377 +48,447 @@ #include #ifdef KOKKOS_ENABLE_CUDA -#include +#include #include -namespace Kokkos { namespace Impl { +namespace Kokkos { +namespace Impl { -template +template struct CudaGetMaxBlockSize; -template -int cuda_get_max_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - return CudaGetMaxBlockSize::get_block_size(f,vector_length, shmem_extra_block,shmem_extra_thread); +template +int cuda_get_max_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + return CudaGetMaxBlockSize::get_block_size( + f, vector_length, shmem_extra_block, shmem_extra_thread); } -template -int cuda_get_max_block_size(const CudaInternal* cuda_instance, const cudaFuncAttributes& attr, const FunctorType& f, const size_t vector_length, - const size_t shmem_block, const size_t shmem_thread) { - - const int min_blocks_per_sm = LaunchBounds::minBperSM == 0 ? - 1 : LaunchBounds::minBperSM ; - const int max_threads_per_block = LaunchBounds::maxTperB == 0 ? - cuda_instance->m_maxThreadsPerBlock : LaunchBounds::maxTperB ; - - const int regs_per_thread = attr.numRegs; - const int regs_per_sm = cuda_instance->m_regsPerSM; - const int shmem_per_sm = cuda_instance->m_shmemPerSM; +template +int cuda_get_max_block_size(const CudaInternal* cuda_instance, + const cudaFuncAttributes& attr, + const FunctorType& f, const size_t vector_length, + const size_t shmem_block, + const size_t shmem_thread) { + const int min_blocks_per_sm = + LaunchBounds::minBperSM == 0 ? 1 : LaunchBounds::minBperSM; + const int max_threads_per_block = LaunchBounds::maxTperB == 0 + ? cuda_instance->m_maxThreadsPerBlock + : LaunchBounds::maxTperB; + + const int regs_per_thread = attr.numRegs; + const int regs_per_sm = cuda_instance->m_regsPerSM; + const int shmem_per_sm = cuda_instance->m_shmemPerSM; const int max_shmem_per_block = cuda_instance->m_maxShmemPerBlock; - const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; - const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; - - int block_size = std::min(attr.maxThreadsPerBlock,max_threads_per_block); - - int functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - int total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - int max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - int max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - int blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; + const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; + + int block_size = std::min(attr.maxThreadsPerBlock, max_threads_per_block); + + int functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + int total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + int max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + int max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + int blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); int threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - int opt_block_size = (blocks_per_sm>=min_blocks_per_sm) ? block_size : 0; + int opt_block_size = (blocks_per_sm >= min_blocks_per_sm) ? block_size : 0; int opt_threads_per_sm = threads_per_sm; - //printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i Achieved: %i %i Opt: %i %i\n",block_size, + // printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i + // Achieved: %i %i Opt: %i %i\n",block_size, // shmem_per_sm,max_shmem_per_block,functor_shmem,total_shmem, // regs_per_sm,regs_per_thread,max_blocks_shmem,max_blocks_regs,blocks_per_sm,threads_per_sm,opt_block_size,opt_threads_per_sm); - block_size-=32; - while ((blocks_per_sm==0) && (block_size>=32)) { - functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + block_size -= 32; + while ((blocks_per_sm == 0) && (block_size >= 32)) { + functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - if((blocks_per_sm >= min_blocks_per_sm) && (blocks_per_sm <= max_blocks_per_sm)) { - if(threads_per_sm>=opt_threads_per_sm) { - opt_block_size = block_size; + if ((blocks_per_sm >= min_blocks_per_sm) && + (blocks_per_sm <= max_blocks_per_sm)) { + if (threads_per_sm >= opt_threads_per_sm) { + opt_block_size = block_size; opt_threads_per_sm = threads_per_sm; } } - //printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i Achieved: %i %i Opt: %i %i\n",block_size, - // shmem_per_sm,max_shmem_per_block,functor_shmem,total_shmem, - // regs_per_sm,regs_per_thread,max_blocks_shmem,max_blocks_regs,blocks_per_sm,threads_per_sm,opt_block_size,opt_threads_per_sm); - block_size-=32; + // printf("BlockSizeMax: %i Shmem: %i %i %i %i Regs: %i %i Blocks: %i %i + // Achieved: %i %i Opt: %i %i\n",block_size, + // shmem_per_sm,max_shmem_per_block,functor_shmem,total_shmem, + // regs_per_sm,regs_per_thread,max_blocks_shmem,max_blocks_regs,blocks_per_sm,threads_per_sm,opt_block_size,opt_threads_per_sm); + block_size -= 32; } return opt_block_size; } - -template -struct CudaGetMaxBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize, true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks; - int blockSize=1024; - int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int blockSize = 1024; + int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, + &numBlocks, cuda_parallel_launch_constant_memory, blockSize, sharedmem); - if(numBlocks>0) return blockSize; - while (blockSize>32 && numBlocks==0) { - blockSize/=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + if (numBlocks > 0) return blockSize; + while (blockSize > 32 && numBlocks == 0) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } - int blockSizeUpperBound = blockSize*2; - while (blockSize0) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int blockSizeUpperBound = blockSize * 2; + while (blockSize < blockSizeUpperBound && numBlocks > 0) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } return blockSize - 32; } }; -template -struct CudaGetMaxBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize, false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks; - unsigned int blockSize=1024; - unsigned int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSize = 1024; + unsigned int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, + &numBlocks, cuda_parallel_launch_local_memory, blockSize, sharedmem); - if(numBlocks>0) return blockSize; - while (blockSize>32 && numBlocks==0) { - blockSize/=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + if (numBlocks > 0) return blockSize; + while (blockSize > 32 && numBlocks == 0) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, + &numBlocks, cuda_parallel_launch_local_memory, blockSize, sharedmem); } - unsigned int blockSizeUpperBound = blockSize*2; - while (blockSize0) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSizeUpperBound = blockSize * 2; + while (blockSize < blockSizeUpperBound && numBlocks > 0) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_local_memory, blockSize, + sharedmem); } return blockSize - 32; } }; -template -struct CudaGetMaxBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize< + DriverType, Kokkos::LaunchBounds, + true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks = 0, oldNumBlocks = 0; - unsigned int blockSize=MaxThreadsPerBlock; - unsigned int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSize = MaxThreadsPerBlock; + unsigned int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + cuda_parallel_launch_constant_memory, + blockSize, sharedmem); - if(static_cast(numBlocks)>=MinBlocksPerSM) return blockSize; + if (static_cast(numBlocks) >= MinBlocksPerSM) + return blockSize; - while (blockSize>32 && static_cast(numBlocks)::value( f , blockSize/vector_length ); + while (blockSize > 32 && + static_cast(numBlocks) < MinBlocksPerSM) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } - unsigned int blockSizeUpperBound = (blockSize*2(numBlocks)>MinBlocksPerSM) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSizeUpperBound = + (blockSize * 2 < MaxThreadsPerBlock ? blockSize * 2 + : MaxThreadsPerBlock); + while (blockSize(numBlocks)> + MinBlocksPerSM) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); oldNumBlocks = numBlocks; cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); } - if(static_cast(oldNumBlocks)>=MinBlocksPerSM) return blockSize - 32; + if (static_cast(oldNumBlocks) >= MinBlocksPerSM) + return blockSize - 32; return -1; } }; -template -struct CudaGetMaxBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { +template +struct CudaGetMaxBlockSize< + DriverType, Kokkos::LaunchBounds, + false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { int numBlocks = 0, oldNumBlocks = 0; - unsigned int blockSize=MaxThreadsPerBlock; - int sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSize = MaxThreadsPerBlock; + int sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); - if(static_cast(numBlocks)>=MinBlocksPerSM) return blockSize; - - while (blockSize>32 && static_cast(numBlocks)::value( f , blockSize/vector_length ); + cuda_parallel_launch_local_memory, + blockSize, sharedmem); + if (static_cast(numBlocks) >= MinBlocksPerSM) + return blockSize; + + while (blockSize > 32 && + static_cast(numBlocks) < MinBlocksPerSM) { + blockSize /= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, + &numBlocks, cuda_parallel_launch_local_memory, blockSize, sharedmem); } - unsigned int blockSizeUpperBound = (blockSize*2(numBlocks)>=MinBlocksPerSM) { - blockSize+=32; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + unsigned int blockSizeUpperBound = + (blockSize * 2 < MaxThreadsPerBlock ? blockSize * 2 + : MaxThreadsPerBlock); + while (blockSize < blockSizeUpperBound && + static_cast(numBlocks) >= MinBlocksPerSM) { + blockSize += 32; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); oldNumBlocks = numBlocks; cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_local_memory, blockSize, + sharedmem); } - if(static_cast(oldNumBlocks)>=MinBlocksPerSM) return blockSize - 32; + if (static_cast(oldNumBlocks) >= MinBlocksPerSM) + return blockSize - 32; return -1; } }; - -template +template struct CudaGetOptBlockSize; -template -int cuda_get_opt_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - return CudaGetOptBlockSize +int cuda_get_opt_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + return CudaGetOptBlockSize< + DriverType, LaunchBounds, + // LaunchBounds::launch_mechanism == Kokkos::Experimental::LaunchDefault ? + // (( CudaTraits::ConstantMemoryUseThreshold < + // sizeof(DriverType) )? // Kokkos::Experimental::CudaLaunchConstantMemory:Kokkos::Experimental::CudaLaunchLocalMemory): // LaunchBounds::launch_mechanism - (CudaTraits::ConstantMemoryUseThreshold < sizeof(DriverType)) - >::get_block_size(f,vector_length,shmem_extra_block,shmem_extra_thread); + (CudaTraits::ConstantMemoryUseThreshold < + sizeof(DriverType))>::get_block_size(f, vector_length, shmem_extra_block, + shmem_extra_thread); } -template -int cuda_get_opt_block_size(const CudaInternal* cuda_instance, const cudaFuncAttributes& attr, const FunctorType& f, const size_t vector_length, - const size_t shmem_block, const size_t shmem_thread) { - - const int min_blocks_per_sm = LaunchBounds::minBperSM == 0 ? - 1 : LaunchBounds::minBperSM ; - const int max_threads_per_block = LaunchBounds::maxTperB == 0 ? - cuda_instance->m_maxThreadsPerBlock : LaunchBounds::maxTperB ; - - const int regs_per_thread = attr.numRegs; - const int regs_per_sm = cuda_instance->m_regsPerSM; - const int shmem_per_sm = cuda_instance->m_shmemPerSM; +template +int cuda_get_opt_block_size(const CudaInternal* cuda_instance, + const cudaFuncAttributes& attr, + const FunctorType& f, const size_t vector_length, + const size_t shmem_block, + const size_t shmem_thread) { + const int min_blocks_per_sm = + LaunchBounds::minBperSM == 0 ? 1 : LaunchBounds::minBperSM; + const int max_threads_per_block = LaunchBounds::maxTperB == 0 + ? cuda_instance->m_maxThreadsPerBlock + : LaunchBounds::maxTperB; + + const int regs_per_thread = attr.numRegs; + const int regs_per_sm = cuda_instance->m_regsPerSM; + const int shmem_per_sm = cuda_instance->m_shmemPerSM; const int max_shmem_per_block = cuda_instance->m_maxShmemPerBlock; - const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; - const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; - - int block_size = std::min(attr.maxThreadsPerBlock,max_threads_per_block); - - int functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - int total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - int max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - int max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - int blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + const int max_blocks_per_sm = cuda_instance->m_maxBlocksPerSM; + const int max_threads_per_sm = cuda_instance->m_maxThreadsPerSM; + + int block_size = std::min(attr.maxThreadsPerBlock, max_threads_per_block); + + int functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + int total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + int max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + int max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + int blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); int threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - int opt_block_size = (blocks_per_sm>=min_blocks_per_sm) ? block_size : 0; + int opt_block_size = (blocks_per_sm >= min_blocks_per_sm) ? block_size : 0; int opt_threads_per_sm = threads_per_sm; - block_size-=32; - while ((block_size>=32)) { - functor_shmem = FunctorTeamShmemSize< FunctorType >::value( f , block_size/vector_length ); - total_shmem = shmem_block + shmem_thread*(block_size/vector_length) + functor_shmem + attr.sharedSizeBytes; - max_blocks_regs = regs_per_sm/(regs_per_thread*block_size); - max_blocks_shmem = (total_shmem0?shmem_per_sm/total_shmem:max_blocks_regs):0; - blocks_per_sm = std::min(max_blocks_regs,max_blocks_shmem); + block_size -= 32; + while ((block_size >= 32)) { + functor_shmem = + FunctorTeamShmemSize::value(f, block_size / vector_length); + total_shmem = shmem_block + shmem_thread * (block_size / vector_length) + + functor_shmem + attr.sharedSizeBytes; + max_blocks_regs = regs_per_sm / (regs_per_thread * block_size); + max_blocks_shmem = + (total_shmem < max_shmem_per_block) + ? (total_shmem > 0 ? shmem_per_sm / total_shmem : max_blocks_regs) + : 0; + blocks_per_sm = std::min(max_blocks_regs, max_blocks_shmem); threads_per_sm = blocks_per_sm * block_size; - if(threads_per_sm > max_threads_per_sm) { - blocks_per_sm = max_threads_per_sm/block_size; + if (threads_per_sm > max_threads_per_sm) { + blocks_per_sm = max_threads_per_sm / block_size; threads_per_sm = blocks_per_sm * block_size; } - if((blocks_per_sm >= min_blocks_per_sm) && (blocks_per_sm <= max_blocks_per_sm)) { - if(threads_per_sm>=opt_threads_per_sm) { - opt_block_size = block_size; + if ((blocks_per_sm >= min_blocks_per_sm) && + (blocks_per_sm <= max_blocks_per_sm)) { + if (threads_per_sm >= opt_threads_per_sm) { + opt_block_size = block_size; opt_threads_per_sm = threads_per_sm; } } - block_size-=32; + block_size -= 32; } return opt_block_size; } -template -struct CudaGetOptBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize, true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; - - while(blockSize<1024) { - blockSize*=2; - - //calculate the occupancy with that optBlockSize and check whether its larger than the largest one found so far - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int maxOccupancy = 0; + int bestBlockSize = 0; + + while (blockSize < 1024) { + blockSize *= 2; + + // calculate the occupancy with that optBlockSize and check whether its + // larger than the largest one found so far + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; - bestBlockSize = blockSize; + &numBlocks, cuda_parallel_launch_constant_memory, + blockSize, sharedmem); + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; + bestBlockSize = blockSize; } } return bestBlockSize; } }; -template -struct CudaGetOptBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize, false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; + int maxOccupancy = 0; + int bestBlockSize = 0; - while(blockSize<1024) { - blockSize*=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + while (blockSize < 1024) { + blockSize *= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); + &numBlocks, cuda_parallel_launch_local_memory, blockSize, + sharedmem); - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; bestBlockSize = blockSize; } } @@ -425,77 +496,96 @@ struct CudaGetOptBlockSize,false> { } }; -template -struct CudaGetOptBlockSize,true> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize< + DriverType, Kokkos::LaunchBounds, + true> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; - int max_threads_per_block = std::min(MaxThreadsPerBlock,cuda_internal_maximum_warp_count()*CudaTraits::WarpSize); - - while(blockSize < max_threads_per_block ) { - blockSize*=2; - - //calculate the occupancy with that optBlockSize and check whether its larger than the largest one found so far - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int maxOccupancy = 0; + int bestBlockSize = 0; + int max_threads_per_block = + std::min(MaxThreadsPerBlock, + cuda_internal_maximum_warp_count() * CudaTraits::WarpSize); + + while (blockSize < max_threads_per_block) { + blockSize *= 2; + + // calculate the occupancy with that optBlockSize and check whether its + // larger than the largest one found so far + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_constant_memory, - blockSize, - sharedmem); - if(numBlocks >= int(MinBlocksPerSM) && blockSize<=int(MaxThreadsPerBlock)) { - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; - bestBlockSize = blockSize; + &numBlocks, + cuda_parallel_launch_constant_memory, + blockSize, sharedmem); + if (numBlocks >= int(MinBlocksPerSM) && + blockSize <= int(MaxThreadsPerBlock)) { + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; + bestBlockSize = blockSize; } } } - if(maxOccupancy > 0) - return bestBlockSize; + if (maxOccupancy > 0) return bestBlockSize; return -1; } }; -template -struct CudaGetOptBlockSize,false> { - static int get_block_size(const typename DriverType::functor_type & f, const size_t vector_length, - const size_t shmem_extra_block, const size_t shmem_extra_thread) { - int blockSize=16; +template +struct CudaGetOptBlockSize< + DriverType, Kokkos::LaunchBounds, + false> { + static int get_block_size(const typename DriverType::functor_type& f, + const size_t vector_length, + const size_t shmem_extra_block, + const size_t shmem_extra_thread) { + int blockSize = 16; int numBlocks; int sharedmem; - int maxOccupancy=0; - int bestBlockSize=0; - int max_threads_per_block = std::min(MaxThreadsPerBlock,cuda_internal_maximum_warp_count()*CudaTraits::WarpSize); - - while(blockSize < max_threads_per_block ) { - blockSize*=2; - sharedmem = shmem_extra_block + shmem_extra_thread*(blockSize/vector_length) + - FunctorTeamShmemSize< typename DriverType::functor_type >::value( f , blockSize/vector_length ); + int maxOccupancy = 0; + int bestBlockSize = 0; + int max_threads_per_block = + std::min(MaxThreadsPerBlock, + cuda_internal_maximum_warp_count() * CudaTraits::WarpSize); + + while (blockSize < max_threads_per_block) { + blockSize *= 2; + sharedmem = + shmem_extra_block + shmem_extra_thread * (blockSize / vector_length) + + FunctorTeamShmemSize::value( + f, blockSize / vector_length); cudaOccupancyMaxActiveBlocksPerMultiprocessor( - &numBlocks, - cuda_parallel_launch_local_memory, - blockSize, - sharedmem); - if(numBlocks >= int(MinBlocksPerSM) && blockSize<=int(MaxThreadsPerBlock)) { - if(maxOccupancy < numBlocks*blockSize) { - maxOccupancy = numBlocks*blockSize; + &numBlocks, + cuda_parallel_launch_local_memory, + blockSize, sharedmem); + if (numBlocks >= int(MinBlocksPerSM) && + blockSize <= int(MaxThreadsPerBlock)) { + if (maxOccupancy < numBlocks * blockSize) { + maxOccupancy = numBlocks * blockSize; bestBlockSize = blockSize; } } } - if(maxOccupancy > 0) - return bestBlockSize; + if (maxOccupancy > 0) return bestBlockSize; return -1; } }; -}} // namespace Kokkos::Impl - -#endif // KOKKOS_ENABLE_CUDA -#endif /* #ifndef KOKKOS_CUDA_INTERNAL_HPP */ +} // namespace Impl +} // namespace Kokkos +#endif // KOKKOS_ENABLE_CUDA +#endif /* #ifndef KOKKOS_CUDA_INTERNAL_HPP */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp index 55c7c782fe..3b674bbb30 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Error.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,22 +48,82 @@ #include #ifdef KOKKOS_ENABLE_CUDA -namespace Kokkos { namespace Impl { +#include + +#include + +namespace Kokkos { +namespace Impl { void cuda_device_synchronize(); -void cuda_internal_error_throw( cudaError e , const char * name, const char * file = NULL, const int line = 0 ); +void cuda_internal_error_throw(cudaError e, const char* name, + const char* file = NULL, const int line = 0); -inline void cuda_internal_safe_call( cudaError e , const char * name, const char * file = NULL, const int line = 0) -{ - if ( cudaSuccess != e ) { cuda_internal_error_throw( e , name, file, line ); } +inline void cuda_internal_safe_call(cudaError e, const char* name, + const char* file = NULL, + const int line = 0) { + if (cudaSuccess != e) { + cuda_internal_error_throw(e, name, file, line); + } } -#define CUDA_SAFE_CALL( call ) \ - Kokkos::Impl::cuda_internal_safe_call( call , #call, __FILE__, __LINE__ ) +#define CUDA_SAFE_CALL(call) \ + Kokkos::Impl::cuda_internal_safe_call(call, #call, __FILE__, __LINE__) + +} // namespace Impl + +namespace Experimental { + +class CudaRawMemoryAllocationFailure : public RawMemoryAllocationFailure { + private: + using base_t = RawMemoryAllocationFailure; + + cudaError_t m_error_code = cudaSuccess; + + static FailureMode get_failure_mode(cudaError_t error_code) { + switch (error_code) { + case cudaErrorMemoryAllocation: return FailureMode::OutOfMemoryError; + case cudaErrorInvalidValue: return FailureMode::InvalidAllocationSize; + // TODO handle cudaErrorNotSupported for cudaMallocManaged + default: return FailureMode::Unknown; + } + } + + public: + // using base_t::base_t; + // would trigger + // + // error: cannot determine the exception specification of the default + // constructor due to a circular dependency + // + // using NVCC 9.1 and gcc 7.4 + CudaRawMemoryAllocationFailure( + size_t arg_attempted_size, size_t arg_attempted_alignment, + FailureMode arg_failure_mode = FailureMode::OutOfMemoryError, + AllocationMechanism arg_mechanism = + AllocationMechanism::StdMalloc) noexcept + : base_t(arg_attempted_size, arg_attempted_alignment, arg_failure_mode, + arg_mechanism) {} + + CudaRawMemoryAllocationFailure(size_t arg_attempted_size, + cudaError_t arg_error_code, + AllocationMechanism arg_mechanism) noexcept + : base_t(arg_attempted_size, /* CudaSpace doesn't handle alignment? */ 1, + get_failure_mode(arg_error_code), arg_mechanism), + m_error_code(arg_error_code) {} + + void append_additional_error_information(std::ostream& o) const override { + if (m_error_code != cudaSuccess) { + o << " The Cuda allocation returned the error code \"\"" + << cudaGetErrorName(m_error_code) << "\"."; + } + } +}; -}} // namespace Kokkos::Impl +} // end namespace Experimental -#endif //KOKKOS_ENABLE_CUDA -#endif //KOKKOS_CUDA_ERROR_HPP +} // namespace Kokkos +#endif // KOKKOS_ENABLE_CUDA +#endif // KOKKOS_CUDA_ERROR_HPP diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp index 0ca9e3c160..b3c7edf67c 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -66,10 +67,34 @@ #include #include +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION +namespace Kokkos { +namespace Impl { + +bool CudaInternal::kokkos_impl_cuda_use_serial_execution_v = false; + +void CudaInternal::cuda_set_serial_execution(bool val) { + CudaInternal::kokkos_impl_cuda_use_serial_execution_v = val; +} +bool CudaInternal::cuda_use_serial_execution() { + return CudaInternal::kokkos_impl_cuda_use_serial_execution_v; +} + +} // namespace Impl +} // namespace Kokkos + +void kokkos_impl_cuda_set_serial_execution(bool val) { + Kokkos::Impl::CudaInternal::cuda_set_serial_execution(val); +} +bool kokkos_impl_cuda_use_serial_execution() { + return Kokkos::Impl::CudaInternal::cuda_use_serial_execution(); +} +#endif + #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -__device__ __constant__ -unsigned long kokkos_impl_cuda_constant_memory_buffer[ Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long) ] ; +__device__ __constant__ unsigned long kokkos_impl_cuda_constant_memory_buffer + [Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long)]; #endif @@ -80,32 +105,28 @@ namespace Impl { namespace { -__global__ -void query_cuda_kernel_arch( int * d_arch ) -{ -#if defined( __CUDA_ARCH__ ) - *d_arch = __CUDA_ARCH__ ; +__global__ void query_cuda_kernel_arch(int *d_arch) { +#if defined(__CUDA_ARCH__) + *d_arch = __CUDA_ARCH__; #else - *d_arch = 0 ; + *d_arch = 0; #endif } /** Query what compute capability is actually launched to the device: */ -int cuda_kernel_arch() -{ - int * d_arch = 0 ; - cudaMalloc( (void **) & d_arch , sizeof(int) ); - query_cuda_kernel_arch<<<1,1>>>( d_arch ); - int arch = 0 ; - cudaMemcpy( & arch , d_arch , sizeof(int) , cudaMemcpyDefault ); - cudaFree( d_arch ); - return arch ; +int cuda_kernel_arch() { + int *d_arch = 0; + cudaMalloc((void **)&d_arch, sizeof(int)); + query_cuda_kernel_arch<<<1, 1>>>(d_arch); + int arch = 0; + cudaMemcpy(&arch, d_arch, sizeof(int), cudaMemcpyDefault); + cudaFree(d_arch); + return arch; } #ifdef KOKKOS_ENABLE_CUDA_UVM -bool cuda_launch_blocking() -{ - const char * env = getenv("CUDA_LAUNCH_BLOCKING"); +bool cuda_launch_blocking() { + const char *env = getenv("CUDA_LAUNCH_BLOCKING"); if (env == 0) return false; @@ -113,21 +134,19 @@ bool cuda_launch_blocking() } #endif -} +} // namespace -void cuda_device_synchronize() -{ - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); -} +void cuda_device_synchronize() { CUDA_SAFE_CALL(cudaDeviceSynchronize()); } -void cuda_internal_error_throw( cudaError e , const char * name, const char * file, const int line ) -{ - std::ostringstream out ; - out << name << " error( " << cudaGetErrorName(e) << "): " << cudaGetErrorString(e); +void cuda_internal_error_throw(cudaError e, const char *name, const char *file, + const int line) { + std::ostringstream out; + out << name << " error( " << cudaGetErrorName(e) + << "): " << cudaGetErrorString(e); if (file) { out << " " << file << ":" << line; } - throw_runtime_exception( out.str() ); + throw_runtime_exception(out.str()); } //---------------------------------------------------------------------------- @@ -180,231 +199,220 @@ void cuda_internal_error_throw( cudaError e , const char * name, const char * fi // int maxThreadsPerMultiProcessor; // }; - namespace { - - class CudaInternalDevices { -public: + public: enum { MAXIMUM_DEVICE_COUNT = 64 }; - struct cudaDeviceProp m_cudaProp[ MAXIMUM_DEVICE_COUNT ] ; - int m_cudaDevCount ; + struct cudaDeviceProp m_cudaProp[MAXIMUM_DEVICE_COUNT]; + int m_cudaDevCount; CudaInternalDevices(); - static const CudaInternalDevices & singleton(); + static const CudaInternalDevices &singleton(); }; -CudaInternalDevices::CudaInternalDevices() -{ +CudaInternalDevices::CudaInternalDevices() { // See 'cudaSetDeviceFlags' for host-device thread interaction // Section 4.4.2.6 of the CUDA Toolkit Reference Manual - CUDA_SAFE_CALL (cudaGetDeviceCount( & m_cudaDevCount ) ); + CUDA_SAFE_CALL(cudaGetDeviceCount(&m_cudaDevCount)); - if(m_cudaDevCount > MAXIMUM_DEVICE_COUNT) { - Kokkos::abort("Sorry, you have more GPUs per node than we thought anybody would ever have. Please report this to github.com/kokkos/kokkos."); + if (m_cudaDevCount > MAXIMUM_DEVICE_COUNT) { + Kokkos::abort( + "Sorry, you have more GPUs per node than we thought anybody would ever " + "have. Please report this to github.com/kokkos/kokkos."); } - for ( int i = 0 ; i < m_cudaDevCount ; ++i ) { - CUDA_SAFE_CALL( cudaGetDeviceProperties( m_cudaProp + i , i ) ); + for (int i = 0; i < m_cudaDevCount; ++i) { + CUDA_SAFE_CALL(cudaGetDeviceProperties(m_cudaProp + i, i)); } } -const CudaInternalDevices & CudaInternalDevices::singleton() -{ - static CudaInternalDevices self ; return self ; -} - +const CudaInternalDevices &CudaInternalDevices::singleton() { + static CudaInternalDevices self; + return self; } +} // namespace int CudaInternal::was_initialized = 0; -int CudaInternal::was_finalized = 0; +int CudaInternal::was_finalized = 0; //---------------------------------------------------------------------------- +void CudaInternal::print_configuration(std::ostream &s) const { + const CudaInternalDevices &dev_info = CudaInternalDevices::singleton(); -void CudaInternal::print_configuration( std::ostream & s ) const -{ - const CudaInternalDevices & dev_info = CudaInternalDevices::singleton(); - -#if defined( KOKKOS_ENABLE_CUDA ) - s << "macro KOKKOS_ENABLE_CUDA : defined" << std::endl ; +#if defined(KOKKOS_ENABLE_CUDA) + s << "macro KOKKOS_ENABLE_CUDA : defined" << std::endl; #endif -#if defined( CUDA_VERSION ) - s << "macro CUDA_VERSION = " << CUDA_VERSION - << " = version " << CUDA_VERSION / 1000 - << "." << ( CUDA_VERSION % 1000 ) / 10 - << std::endl ; +#if defined(CUDA_VERSION) + s << "macro CUDA_VERSION = " << CUDA_VERSION << " = version " + << CUDA_VERSION / 1000 << "." << (CUDA_VERSION % 1000) / 10 << std::endl; #endif - for ( int i = 0 ; i < dev_info.m_cudaDevCount ; ++i ) { - s << "Kokkos::Cuda[ " << i << " ] " - << dev_info.m_cudaProp[i].name - << " capability " << dev_info.m_cudaProp[i].major << "." << dev_info.m_cudaProp[i].minor - << ", Total Global Memory: " << human_memory_size(dev_info.m_cudaProp[i].totalGlobalMem) - << ", Shared Memory per Block: " << human_memory_size(dev_info.m_cudaProp[i].sharedMemPerBlock); - if ( m_cudaDev == i ) s << " : Selected" ; - s << std::endl ; + for (int i = 0; i < dev_info.m_cudaDevCount; ++i) { + s << "Kokkos::Cuda[ " << i << " ] " << dev_info.m_cudaProp[i].name + << " capability " << dev_info.m_cudaProp[i].major << "." + << dev_info.m_cudaProp[i].minor << ", Total Global Memory: " + << human_memory_size(dev_info.m_cudaProp[i].totalGlobalMem) + << ", Shared Memory per Block: " + << human_memory_size(dev_info.m_cudaProp[i].sharedMemPerBlock); + if (m_cudaDev == i) s << " : Selected"; + s << std::endl; } } //---------------------------------------------------------------------------- -CudaInternal::~CudaInternal() -{ - if ( m_stream || - m_scratchSpace || - m_scratchFlags || - m_scratchUnified || - m_scratchConcurrentBitset ) { +CudaInternal::~CudaInternal() { + if (m_stream || m_scratchSpace || m_scratchFlags || m_scratchUnified || + m_scratchConcurrentBitset) { std::cerr << "Kokkos::Cuda ERROR: Failed to call Kokkos::Cuda::finalize()" - << std::endl ; + << std::endl; std::cerr.flush(); } - m_cudaDev = -1 ; - m_cudaArch = -1 ; - m_multiProcCount = 0 ; - m_maxWarpCount = 0 ; - m_maxBlock = 0 ; - m_maxSharedWords = 0 ; - m_maxConcurrency = 0 ; - m_scratchSpaceCount = 0 ; - m_scratchFlagsCount = 0 ; - m_scratchUnifiedCount = 0 ; - m_scratchUnifiedSupported = 0 ; - m_streamCount = 0 ; - m_scratchSpace = 0 ; - m_scratchFlags = 0 ; - m_scratchUnified = 0 ; - m_scratchConcurrentBitset = 0 ; - m_stream = 0 ; -} - -int CudaInternal::verify_is_initialized( const char * const label ) const -{ - if ( m_cudaDev < 0 ) { - std::cerr << "Kokkos::Cuda::" << label << " : ERROR device not initialized" << std::endl ; - } - return 0 <= m_cudaDev ; + m_cudaDev = -1; + m_cudaArch = -1; + m_multiProcCount = 0; + m_maxWarpCount = 0; + m_maxBlock = 0; + m_maxSharedWords = 0; + m_maxConcurrency = 0; + m_scratchSpaceCount = 0; + m_scratchFlagsCount = 0; + m_scratchUnifiedCount = 0; + m_scratchUnifiedSupported = 0; + m_streamCount = 0; + m_scratchSpace = 0; + m_scratchFlags = 0; + m_scratchUnified = 0; + m_scratchConcurrentBitset = 0; + m_stream = 0; } -CudaInternal & CudaInternal::singleton() -{ - static CudaInternal self ; - return self ; +int CudaInternal::verify_is_initialized(const char *const label) const { + if (m_cudaDev < 0) { + std::cerr << "Kokkos::Cuda::" << label << " : ERROR device not initialized" + << std::endl; + } + return 0 <= m_cudaDev; } -void CudaInternal::fence() const { - cudaStreamSynchronize(m_stream); + +CudaInternal &CudaInternal::singleton() { + static CudaInternal self; + return self; } +void CudaInternal::fence() const { cudaStreamSynchronize(m_stream); } -void CudaInternal::initialize( int cuda_device_id , cudaStream_t stream ) -{ - if ( was_finalized ) Kokkos::abort("Calling Cuda::initialize after Cuda::finalize is illegal\n"); +void CudaInternal::initialize(int cuda_device_id, cudaStream_t stream) { + if (was_finalized) + Kokkos::abort("Calling Cuda::initialize after Cuda::finalize is illegal\n"); was_initialized = 1; - if ( is_initialized() ) return; + if (is_initialized()) return; enum { WordSize = sizeof(size_type) }; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - if ( ! HostSpace::execution_space::is_initialized() ) { + if (!HostSpace::execution_space::is_initialized()) { #else - if ( ! HostSpace::execution_space::impl_is_initialized() ) { + if (!HostSpace::execution_space::impl_is_initialized()) { #endif - const std::string msg("Cuda::initialize ERROR : HostSpace::execution_space is not initialized"); - throw_runtime_exception( msg ); + const std::string msg( + "Cuda::initialize ERROR : HostSpace::execution_space is not " + "initialized"); + throw_runtime_exception(msg); } - const CudaInternalDevices & dev_info = CudaInternalDevices::singleton(); + const CudaInternalDevices &dev_info = CudaInternalDevices::singleton(); - const bool ok_init = 0 == m_scratchSpace || 0 == m_scratchFlags ; + const bool ok_init = 0 == m_scratchSpace || 0 == m_scratchFlags; - const bool ok_id = 0 <= cuda_device_id && - cuda_device_id < dev_info.m_cudaDevCount ; + const bool ok_id = + 0 <= cuda_device_id && cuda_device_id < dev_info.m_cudaDevCount; // Need device capability 3.0 or better - const bool ok_dev = ok_id && - ( 3 <= dev_info.m_cudaProp[ cuda_device_id ].major && - 0 <= dev_info.m_cudaProp[ cuda_device_id ].minor ); - - if ( ok_init && ok_dev ) { + const bool ok_dev = + ok_id && (3 <= dev_info.m_cudaProp[cuda_device_id].major && + 0 <= dev_info.m_cudaProp[cuda_device_id].minor); - const struct cudaDeviceProp & cudaProp = - dev_info.m_cudaProp[ cuda_device_id ]; + if (ok_init && ok_dev) { + const struct cudaDeviceProp &cudaProp = dev_info.m_cudaProp[cuda_device_id]; - m_cudaDev = cuda_device_id ; + m_cudaDev = cuda_device_id; - CUDA_SAFE_CALL( cudaSetDevice( m_cudaDev ) ); + CUDA_SAFE_CALL(cudaSetDevice(m_cudaDev)); Kokkos::Impl::cuda_device_synchronize(); // Query what compute capability architecture a kernel executes: m_cudaArch = cuda_kernel_arch(); int compiled_major = m_cudaArch / 100; - int compiled_minor = ( m_cudaArch % 100 ) / 10; + int compiled_minor = (m_cudaArch % 100) / 10; - if ( compiled_major < 5 && cudaProp.major >= 5 ) { + if (compiled_major < 5 && cudaProp.major >= 5) { std::stringstream ss; - ss << "Kokkos::Cuda::initialize ERROR: running kernels compiled for compute capability " + ss << "Kokkos::Cuda::initialize ERROR: running kernels compiled for " + "compute capability " << compiled_major << "." << compiled_minor - << " (< 5.0) on device with compute capability " - << cudaProp.major << "." << cudaProp.minor - << " (>=5.0), this would give incorrect results!" - << std::endl ; + << " (< 5.0) on device with compute capability " << cudaProp.major + << "." << cudaProp.minor + << " (>=5.0), this would give incorrect results!" << std::endl; std::string msg = ss.str(); - Kokkos::abort( msg.c_str() ); + Kokkos::abort(msg.c_str()); } - if ( Kokkos::show_warnings() && (compiled_major != cudaProp.major || compiled_minor != cudaProp.minor) ) { - std::cerr << "Kokkos::Cuda::initialize WARNING: running kernels compiled for compute capability " + if (Kokkos::show_warnings() && (compiled_major != cudaProp.major || + compiled_minor != cudaProp.minor)) { + std::cerr << "Kokkos::Cuda::initialize WARNING: running kernels compiled " + "for compute capability " << compiled_major << "." << compiled_minor - << " on device with compute capability " - << cudaProp.major << "." << cudaProp.minor + << " on device with compute capability " << cudaProp.major + << "." << cudaProp.minor << " , this will likely reduce potential performance." - << std::endl ; + << std::endl; } // number of multiprocessors - m_multiProcCount = cudaProp.multiProcessorCount ; + m_multiProcCount = cudaProp.multiProcessorCount; //---------------------------------- // Maximum number of warps, // at most one warp per thread in a warp for reduction. - m_maxWarpCount = cudaProp.maxThreadsPerBlock / Impl::CudaTraits::WarpSize ; + m_maxWarpCount = cudaProp.maxThreadsPerBlock / Impl::CudaTraits::WarpSize; - if ( Impl::CudaTraits::WarpSize < m_maxWarpCount ) { - m_maxWarpCount = Impl::CudaTraits::WarpSize ; + if (Impl::CudaTraits::WarpSize < m_maxWarpCount) { + m_maxWarpCount = Impl::CudaTraits::WarpSize; } - m_maxSharedWords = cudaProp.sharedMemPerBlock / WordSize ; + m_maxSharedWords = cudaProp.sharedMemPerBlock / WordSize; //---------------------------------- // Maximum number of blocks: - m_maxBlock = cudaProp.maxGridSize[0] ; + m_maxBlock = cudaProp.maxGridSize[0]; - m_shmemPerSM = cudaProp.sharedMemPerMultiprocessor ; - m_maxShmemPerBlock = cudaProp.sharedMemPerBlock ; - m_regsPerSM = cudaProp.regsPerMultiprocessor ; - m_maxBlocksPerSM = m_cudaArch < 500 ? 16 : ( - m_cudaArch < 750 ? 32 : ( - m_cudaArch == 750 ? 16 : 32)); - m_maxThreadsPerSM = cudaProp.maxThreadsPerMultiProcessor ; - m_maxThreadsPerBlock = cudaProp.maxThreadsPerBlock ; + m_shmemPerSM = cudaProp.sharedMemPerMultiprocessor; + m_maxShmemPerBlock = cudaProp.sharedMemPerBlock; + m_regsPerSM = cudaProp.regsPerMultiprocessor; + m_maxBlocksPerSM = + m_cudaArch < 500 + ? 16 + : (m_cudaArch < 750 ? 32 : (m_cudaArch == 750 ? 16 : 32)); + m_maxThreadsPerSM = cudaProp.maxThreadsPerMultiProcessor; + m_maxThreadsPerBlock = cudaProp.maxThreadsPerBlock; //---------------------------------- - m_scratchUnifiedSupported = cudaProp.unifiedAddressing ; + m_scratchUnifiedSupported = cudaProp.unifiedAddressing; - if ( Kokkos::show_warnings() && ! m_scratchUnifiedSupported ) { - std::cerr << "Kokkos::Cuda device " - << cudaProp.name << " capability " + if (Kokkos::show_warnings() && !m_scratchUnifiedSupported) { + std::cerr << "Kokkos::Cuda device " << cudaProp.name << " capability " << cudaProp.major << "." << cudaProp.minor << " does not support unified virtual address space" - << std::endl ; + << std::endl; } //---------------------------------- @@ -413,345 +421,362 @@ void CudaInternal::initialize( int cuda_device_id , cudaStream_t stream ) // Allocate some initial space. This will grow as needed. { - const unsigned reduce_block_count = m_maxWarpCount * Impl::CudaTraits::WarpSize ; + const unsigned reduce_block_count = + m_maxWarpCount * Impl::CudaTraits::WarpSize; - (void) scratch_unified( 16 * sizeof(size_type) ); - (void) scratch_flags( reduce_block_count * 2 * sizeof(size_type) ); - (void) scratch_space( reduce_block_count * 16 * sizeof(size_type) ); + (void)scratch_unified(16 * sizeof(size_type)); + (void)scratch_flags(reduce_block_count * 2 * sizeof(size_type)); + (void)scratch_space(reduce_block_count * 16 * sizeof(size_type)); } //---------------------------------- // Concurrent bitset for obtaining unique tokens from within // an executing kernel. { - - m_maxConcurrency = - m_maxThreadsPerSM * cudaProp.multiProcessorCount ; + m_maxConcurrency = m_maxThreadsPerSM * cudaProp.multiProcessorCount; const int32_t buffer_bound = - Kokkos::Impl::concurrent_bitset::buffer_bound( m_maxConcurrency ); + Kokkos::Impl::concurrent_bitset::buffer_bound(m_maxConcurrency); // Allocate and initialize uint32_t[ buffer_bound ] - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; - - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchBitset" - , sizeof(uint32_t) * buffer_bound ); + typedef Kokkos::Impl::SharedAllocationRecord + Record; - Record::increment( r ); + Record *const r = + Record::allocate(Kokkos::CudaSpace(), "InternalScratchBitset", + sizeof(uint32_t) * buffer_bound); - m_scratchConcurrentBitset = reinterpret_cast( r->data() ); + Record::increment(r); - CUDA_SAFE_CALL( cudaMemset( m_scratchConcurrentBitset , 0 , sizeof(uint32_t) * buffer_bound ) ); + m_scratchConcurrentBitset = reinterpret_cast(r->data()); + CUDA_SAFE_CALL(cudaMemset(m_scratchConcurrentBitset, 0, + sizeof(uint32_t) * buffer_bound)); } //---------------------------------- - } - else { + } else { + std::ostringstream msg; + msg << "Kokkos::Cuda::initialize(" << cuda_device_id << ") FAILED"; - std::ostringstream msg ; - msg << "Kokkos::Cuda::initialize(" << cuda_device_id << ") FAILED" ; - - if ( ! ok_init ) { - msg << " : Already initialized" ; + if (!ok_init) { + msg << " : Already initialized"; } - if ( ! ok_id ) { + if (!ok_id) { msg << " : Device identifier out of range " - << "[0.." << dev_info.m_cudaDevCount << "]" ; - } - else if ( ! ok_dev ) { - msg << " : Device " ; - msg << dev_info.m_cudaProp[ cuda_device_id ].major ; - msg << "." ; - msg << dev_info.m_cudaProp[ cuda_device_id ].minor ; - msg << " has insufficient capability, required 3.0 or better" ; + << "[0.." << dev_info.m_cudaDevCount << "]"; + } else if (!ok_dev) { + msg << " : Device "; + msg << dev_info.m_cudaProp[cuda_device_id].major; + msg << "."; + msg << dev_info.m_cudaProp[cuda_device_id].minor; + msg << " has insufficient capability, required 3.0 or better"; } - Kokkos::Impl::throw_runtime_exception( msg.str() ); + Kokkos::Impl::throw_runtime_exception(msg.str()); } - #ifdef KOKKOS_ENABLE_CUDA_UVM - if( Kokkos::show_warnings() && !cuda_launch_blocking() ) { - std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into UVMSpace by default" << std::endl; - std::cerr << " without setting CUDA_LAUNCH_BLOCKING=1." << std::endl; - std::cerr << " The code must call Cuda().fence() after each kernel" << std::endl; - std::cerr << " or will likely crash when accessing data on the host." << std::endl; - } +#ifdef KOKKOS_ENABLE_CUDA_UVM + if (Kokkos::show_warnings() && !cuda_launch_blocking()) { + std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into " + "UVMSpace by default" + << std::endl; + std::cerr << " without setting " + "CUDA_LAUNCH_BLOCKING=1." + << std::endl; + std::cerr << " The code must call " + "Cuda().fence() after each kernel" + << std::endl; + std::cerr << " or will likely crash when " + "accessing data on the host." + << std::endl; + } - const char * env_force_device_alloc = getenv("CUDA_MANAGED_FORCE_DEVICE_ALLOC"); - bool force_device_alloc; - if (env_force_device_alloc == 0) force_device_alloc=false; - else force_device_alloc=atoi(env_force_device_alloc)!=0; - - const char * env_visible_devices = getenv("CUDA_VISIBLE_DEVICES"); - bool visible_devices_one=true; - if (env_visible_devices == 0) visible_devices_one=false; - - if( Kokkos::show_warnings() && (!visible_devices_one && !force_device_alloc) ) { - std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into UVMSpace by default" << std::endl; - std::cerr << " without setting CUDA_MANAGED_FORCE_DEVICE_ALLOC=1 or " << std::endl; - std::cerr << " setting CUDA_VISIBLE_DEVICES." << std::endl; - std::cerr << " This could on multi GPU systems lead to severe performance" << std::endl; - std::cerr << " penalties." << std::endl; - } - #endif + const char *env_force_device_alloc = + getenv("CUDA_MANAGED_FORCE_DEVICE_ALLOC"); + bool force_device_alloc; + if (env_force_device_alloc == 0) + force_device_alloc = false; + else + force_device_alloc = atoi(env_force_device_alloc) != 0; + + const char *env_visible_devices = getenv("CUDA_VISIBLE_DEVICES"); + bool visible_devices_one = true; + if (env_visible_devices == 0) visible_devices_one = false; + + if (Kokkos::show_warnings() && + (!visible_devices_one && !force_device_alloc)) { + std::cerr << "Kokkos::Cuda::initialize WARNING: Cuda is allocating into " + "UVMSpace by default" + << std::endl; + std::cerr << " without setting " + "CUDA_MANAGED_FORCE_DEVICE_ALLOC=1 or " + << std::endl; + std::cerr + << " setting CUDA_VISIBLE_DEVICES." + << std::endl; + std::cerr << " This could on multi GPU " + "systems lead to severe performance" + << std::endl; + std::cerr << " penalties." << std::endl; + } +#endif - #ifdef KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API +#ifdef KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API cudaThreadSetCacheConfig(cudaFuncCachePreferShared); - #else +#else cudaDeviceSetCacheConfig(cudaFuncCachePreferShared); - #endif +#endif // Init the array for used for arbitrarily sized atomics - if(stream == 0) - Impl::initialize_host_cuda_lock_arrays(); + if (stream == 0) Impl::initialize_host_cuda_lock_arrays(); m_stream = stream; } //---------------------------------------------------------------------------- -typedef Cuda::size_type ScratchGrain[ Impl::CudaTraits::WarpSize ] ; +typedef Cuda::size_type ScratchGrain[Impl::CudaTraits::WarpSize]; enum { sizeScratchGrain = sizeof(ScratchGrain) }; +Cuda::size_type *CudaInternal::scratch_flags(const Cuda::size_type size) const { + if (verify_is_initialized("scratch_flags") && + m_scratchFlagsCount * sizeScratchGrain < size) { + m_scratchFlagsCount = (size + sizeScratchGrain - 1) / sizeScratchGrain; -Cuda::size_type * -CudaInternal::scratch_flags( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_flags") && m_scratchFlagsCount * sizeScratchGrain < size ) { - - - m_scratchFlagsCount = ( size + sizeScratchGrain - 1 ) / sizeScratchGrain ; - - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - if( m_scratchFlags ) - Record::decrement( Record::get_record( m_scratchFlags ) ); + if (m_scratchFlags) Record::decrement(Record::get_record(m_scratchFlags)); - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchFlags" - , ( sizeof( ScratchGrain ) * m_scratchFlagsCount ) ); + Record *const r = + Record::allocate(Kokkos::CudaSpace(), "InternalScratchFlags", + (sizeof(ScratchGrain) * m_scratchFlagsCount)); - Record::increment( r ); + Record::increment(r); - m_scratchFlags = reinterpret_cast( r->data() ); + m_scratchFlags = reinterpret_cast(r->data()); - CUDA_SAFE_CALL( cudaMemset( m_scratchFlags , 0 , m_scratchFlagsCount * sizeScratchGrain ) ); + CUDA_SAFE_CALL( + cudaMemset(m_scratchFlags, 0, m_scratchFlagsCount * sizeScratchGrain)); } - return m_scratchFlags ; + return m_scratchFlags; } -Cuda::size_type * -CudaInternal::scratch_space( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_space") && m_scratchSpaceCount * sizeScratchGrain < size ) { - - m_scratchSpaceCount = ( size + sizeScratchGrain - 1 ) / sizeScratchGrain ; +Cuda::size_type *CudaInternal::scratch_space(const Cuda::size_type size) const { + if (verify_is_initialized("scratch_space") && + m_scratchSpaceCount * sizeScratchGrain < size) { + m_scratchSpaceCount = (size + sizeScratchGrain - 1) / sizeScratchGrain; - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - if( m_scratchSpace ) - Record::decrement( Record::get_record( m_scratchSpace ) ); + if (m_scratchSpace) Record::decrement(Record::get_record(m_scratchSpace)); - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchSpace" - , ( sizeof( ScratchGrain ) * m_scratchSpaceCount ) ); + Record *const r = + Record::allocate(Kokkos::CudaSpace(), "InternalScratchSpace", + (sizeof(ScratchGrain) * m_scratchSpaceCount)); - Record::increment( r ); + Record::increment(r); - m_scratchSpace = reinterpret_cast( r->data() ); + m_scratchSpace = reinterpret_cast(r->data()); } - return m_scratchSpace ; + return m_scratchSpace; } -Cuda::size_type * -CudaInternal::scratch_unified( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_unified") && - m_scratchUnifiedSupported && m_scratchUnifiedCount * sizeScratchGrain < size ) { +Cuda::size_type *CudaInternal::scratch_unified( + const Cuda::size_type size) const { + if (verify_is_initialized("scratch_unified") && m_scratchUnifiedSupported && + m_scratchUnifiedCount * sizeScratchGrain < size) { + m_scratchUnifiedCount = (size + sizeScratchGrain - 1) / sizeScratchGrain; - m_scratchUnifiedCount = ( size + sizeScratchGrain - 1 ) / sizeScratchGrain ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > Record ; + if (m_scratchUnified) + Record::decrement(Record::get_record(m_scratchUnified)); - if( m_scratchUnified ) - Record::decrement( Record::get_record( m_scratchUnified ) ); + Record *const r = Record::allocate( + Kokkos::CudaHostPinnedSpace(), "InternalScratchUnified", + (sizeof(ScratchGrain) * m_scratchUnifiedCount)); - Record * const r = Record::allocate( Kokkos::CudaHostPinnedSpace() - , "InternalScratchUnified" - , ( sizeof( ScratchGrain ) * m_scratchUnifiedCount ) ); + Record::increment(r); - Record::increment( r ); - - m_scratchUnified = reinterpret_cast( r->data() ); + m_scratchUnified = reinterpret_cast(r->data()); } - return m_scratchUnified ; + return m_scratchUnified; } -Cuda::size_type * -CudaInternal::scratch_functor( const Cuda::size_type size ) const -{ - if ( verify_is_initialized("scratch_functor") && - m_scratchFunctorSize < size ) { - - m_scratchFunctorSize = size ; +Cuda::size_type *CudaInternal::scratch_functor( + const Cuda::size_type size) const { + if (verify_is_initialized("scratch_functor") && m_scratchFunctorSize < size) { + m_scratchFunctorSize = size; - typedef Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > Record ; + typedef Kokkos::Impl::SharedAllocationRecord + Record; - if( m_scratchFunctor ) - Record::decrement( Record::get_record( m_scratchFunctor ) ); + if (m_scratchFunctor) + Record::decrement(Record::get_record(m_scratchFunctor)); - Record * const r = Record::allocate( Kokkos::CudaSpace() - , "InternalScratchFunctor" - , m_scratchFunctorSize ); + Record *const r = Record::allocate( + Kokkos::CudaSpace(), "InternalScratchFunctor", m_scratchFunctorSize); - Record::increment( r ); + Record::increment(r); - m_scratchFunctor = reinterpret_cast( r->data() ); + m_scratchFunctor = reinterpret_cast(r->data()); } - return m_scratchFunctor ; + return m_scratchFunctor; } //---------------------------------------------------------------------------- -void CudaInternal::finalize() -{ +void CudaInternal::finalize() { was_finalized = 1; - if ( 0 != m_scratchSpace || 0 != m_scratchFlags ) { - + if (0 != m_scratchSpace || 0 != m_scratchFlags) { Impl::finalize_host_cuda_lock_arrays(); - if(m_stream!=0) cudaStreamDestroy(m_stream); - - typedef Kokkos::Impl::SharedAllocationRecord< CudaSpace > RecordCuda ; - typedef Kokkos::Impl::SharedAllocationRecord< CudaHostPinnedSpace > RecordHost ; - - RecordCuda::decrement( RecordCuda::get_record( m_scratchFlags ) ); - RecordCuda::decrement( RecordCuda::get_record( m_scratchSpace ) ); - RecordHost::decrement( RecordHost::get_record( m_scratchUnified ) ); - RecordCuda::decrement( RecordCuda::get_record( m_scratchConcurrentBitset ) ); - if(m_scratchFunctorSize>0) - RecordCuda::decrement( RecordCuda::get_record( m_scratchFunctor ) ); - - m_cudaDev = -1 ; - m_multiProcCount = 0 ; - m_maxWarpCount = 0 ; - m_maxBlock = 0 ; - m_maxSharedWords = 0 ; - m_scratchSpaceCount = 0 ; - m_scratchFlagsCount = 0 ; - m_scratchUnifiedCount = 0 ; - m_streamCount = 0 ; - m_scratchSpace = 0 ; - m_scratchFlags = 0 ; - m_scratchUnified = 0 ; - m_scratchConcurrentBitset = 0 ; - m_stream = 0 ; + if (m_stream != 0) cudaStreamDestroy(m_stream); + + typedef Kokkos::Impl::SharedAllocationRecord RecordCuda; + typedef Kokkos::Impl::SharedAllocationRecord + RecordHost; + + RecordCuda::decrement(RecordCuda::get_record(m_scratchFlags)); + RecordCuda::decrement(RecordCuda::get_record(m_scratchSpace)); + RecordHost::decrement(RecordHost::get_record(m_scratchUnified)); + RecordCuda::decrement(RecordCuda::get_record(m_scratchConcurrentBitset)); + if (m_scratchFunctorSize > 0) + RecordCuda::decrement(RecordCuda::get_record(m_scratchFunctor)); + + m_cudaDev = -1; + m_multiProcCount = 0; + m_maxWarpCount = 0; + m_maxBlock = 0; + m_maxSharedWords = 0; + m_scratchSpaceCount = 0; + m_scratchFlagsCount = 0; + m_scratchUnifiedCount = 0; + m_streamCount = 0; + m_scratchSpace = 0; + m_scratchFlags = 0; + m_scratchUnified = 0; + m_scratchConcurrentBitset = 0; + m_stream = 0; } } //---------------------------------------------------------------------------- -Cuda::size_type cuda_internal_multiprocessor_count() -{ return CudaInternal::singleton().m_multiProcCount ; } +Cuda::size_type cuda_internal_multiprocessor_count() { + return CudaInternal::singleton().m_multiProcCount; +} -CudaSpace::size_type cuda_internal_maximum_concurrent_block_count() -{ - #if defined(KOKKOS_ARCH_KEPLER) +CudaSpace::size_type cuda_internal_maximum_concurrent_block_count() { +#if defined(KOKKOS_ARCH_KEPLER) // Compute capability 3.0 through 3.7 enum : int { max_resident_blocks_per_multiprocessor = 16 }; - #else +#else // Compute capability 5.0 through 6.2 enum : int { max_resident_blocks_per_multiprocessor = 32 }; - #endif - return CudaInternal::singleton().m_multiProcCount - * max_resident_blocks_per_multiprocessor ; +#endif + return CudaInternal::singleton().m_multiProcCount * + max_resident_blocks_per_multiprocessor; }; -Cuda::size_type cuda_internal_maximum_warp_count() -{ return CudaInternal::singleton().m_maxWarpCount ; } - -Cuda::size_type cuda_internal_maximum_grid_count() -{ return CudaInternal::singleton().m_maxBlock ; } +Cuda::size_type cuda_internal_maximum_warp_count() { + return CudaInternal::singleton().m_maxWarpCount; +} -Cuda::size_type cuda_internal_maximum_shared_words() -{ return CudaInternal::singleton().m_maxSharedWords ; } +Cuda::size_type cuda_internal_maximum_grid_count() { + return CudaInternal::singleton().m_maxBlock; +} -Cuda::size_type * cuda_internal_scratch_space( const Cuda& instance, const Cuda::size_type size ) -{ return instance.impl_internal_space_instance()->scratch_space( size ); } +Cuda::size_type cuda_internal_maximum_shared_words() { + return CudaInternal::singleton().m_maxSharedWords; +} -Cuda::size_type * cuda_internal_scratch_flags( const Cuda& instance, const Cuda::size_type size ) -{ return instance.impl_internal_space_instance()->scratch_flags( size ); } +Cuda::size_type *cuda_internal_scratch_space(const Cuda &instance, + const Cuda::size_type size) { + return instance.impl_internal_space_instance()->scratch_space(size); +} -Cuda::size_type * cuda_internal_scratch_unified( const Cuda& instance, const Cuda::size_type size ) -{ return instance.impl_internal_space_instance()->scratch_unified( size ); } +Cuda::size_type *cuda_internal_scratch_flags(const Cuda &instance, + const Cuda::size_type size) { + return instance.impl_internal_space_instance()->scratch_flags(size); +} +Cuda::size_type *cuda_internal_scratch_unified(const Cuda &instance, + const Cuda::size_type size) { + return instance.impl_internal_space_instance()->scratch_unified(size); +} -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -Cuda::size_type Cuda::detect_device_count() -{ return Impl::CudaInternalDevices::singleton().m_cudaDevCount ; } +Cuda::size_type Cuda::detect_device_count() { + return Impl::CudaInternalDevices::singleton().m_cudaDevCount; +} -int Cuda::concurrency() -{ return Impl::CudaInternal::singleton().m_maxConcurrency ; } +int Cuda::concurrency() { + return Impl::CudaInternal::singleton().m_maxConcurrency; +} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE int Cuda::is_initialized() #else int Cuda::impl_is_initialized() #endif -{ return Impl::CudaInternal::singleton().is_initialized(); } +{ + return Impl::CudaInternal::singleton().is_initialized(); +} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -void Cuda::initialize( const Cuda::SelectDevice config , size_t num_instances ) +void Cuda::initialize(const Cuda::SelectDevice config, size_t num_instances) #else -void Cuda::impl_initialize( const Cuda::SelectDevice config , size_t num_instances ) +void Cuda::impl_initialize(const Cuda::SelectDevice config, + size_t num_instances) #endif { - Impl::CudaInternal::singleton().initialize( config.cuda_device_id , 0 ); + Impl::CudaInternal::singleton().initialize(config.cuda_device_id, 0); - #if defined(KOKKOS_ENABLE_PROFILING) - Kokkos::Profiling::initialize(); - #endif +#if defined(KOKKOS_ENABLE_PROFILING) + Kokkos::Profiling::initialize(); +#endif } -std::vector -Cuda::detect_device_arch() -{ - const Impl::CudaInternalDevices & s = Impl::CudaInternalDevices::singleton(); +std::vector Cuda::detect_device_arch() { + const Impl::CudaInternalDevices &s = Impl::CudaInternalDevices::singleton(); - std::vector output( s.m_cudaDevCount ); + std::vector output(s.m_cudaDevCount); - for ( int i = 0 ; i < s.m_cudaDevCount ; ++i ) { - output[i] = s.m_cudaProp[i].major * 100 + s.m_cudaProp[i].minor ; + for (int i = 0; i < s.m_cudaDevCount; ++i) { + output[i] = s.m_cudaProp[i].major * 100 + s.m_cudaProp[i].minor; } - return output ; + return output; } -Cuda::size_type Cuda::device_arch() -{ - const int dev_id = Impl::CudaInternal::singleton().m_cudaDev ; +Cuda::size_type Cuda::device_arch() { + const int dev_id = Impl::CudaInternal::singleton().m_cudaDev; - int dev_arch = 0 ; + int dev_arch = 0; - if ( 0 <= dev_id ) { - const struct cudaDeviceProp & cudaProp = - Impl::CudaInternalDevices::singleton().m_cudaProp[ dev_id ] ; + if (0 <= dev_id) { + const struct cudaDeviceProp &cudaProp = + Impl::CudaInternalDevices::singleton().m_cudaProp[dev_id]; - dev_arch = cudaProp.major * 100 + cudaProp.minor ; + dev_arch = cudaProp.major * 100 + cudaProp.minor; } - return dev_arch ; + return dev_arch; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE @@ -762,71 +787,62 @@ void Cuda::impl_finalize() { Impl::CudaInternal::singleton().finalize(); - #if defined(KOKKOS_ENABLE_PROFILING) - Kokkos::Profiling::finalize(); - #endif +#if defined(KOKKOS_ENABLE_PROFILING) + Kokkos::Profiling::finalize(); +#endif } -Cuda::Cuda() - : m_space_instance( &Impl::CudaInternal::singleton() ) -{ - Impl::CudaInternal::singleton().verify_is_initialized( "Cuda instance constructor" ); +Cuda::Cuda() : m_space_instance(&Impl::CudaInternal::singleton()) { + Impl::CudaInternal::singleton().verify_is_initialized( + "Cuda instance constructor"); } -Cuda::Cuda(cudaStream_t stream) - : m_space_instance(new Impl::CudaInternal) -{ - Impl::CudaInternal::singleton().verify_is_initialized( "Cuda instance constructor" ); - m_space_instance->initialize(Impl::CudaInternal::singleton().m_cudaDev,stream); +Cuda::Cuda(cudaStream_t stream) : m_space_instance(new Impl::CudaInternal) { + Impl::CudaInternal::singleton().verify_is_initialized( + "Cuda instance constructor"); + m_space_instance->initialize(Impl::CudaInternal::singleton().m_cudaDev, + stream); } -void Cuda::print_configuration( std::ostream & s , const bool ) -{ Impl::CudaInternal::singleton().print_configuration( s ); } +void Cuda::print_configuration(std::ostream &s, const bool) { + Impl::CudaInternal::singleton().print_configuration(s); +} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -bool Cuda::sleep() { return false ; } +bool Cuda::sleep() { return false; } -bool Cuda::wake() { return true ; } +bool Cuda::wake() { return true; } #endif -void Cuda::impl_static_fence() -{ - Kokkos::Impl::cuda_device_synchronize(); -} +void Cuda::impl_static_fence() { Kokkos::Impl::cuda_device_synchronize(); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -void Cuda::fence() { - impl_static_fence(); -} +void Cuda::fence() { impl_static_fence(); } #else -void Cuda::fence() const { - m_space_instance->fence(); -} +void Cuda::fence() const { m_space_instance->fence(); } #endif -const char* Cuda::name() { return "Cuda"; } +const char *Cuda::name() { return "Cuda"; } -cudaStream_t Cuda::cuda_stream() const { return m_space_instance->m_stream ; } -int Cuda::cuda_device() const { return m_space_instance->m_cudaDev ; } +cudaStream_t Cuda::cuda_stream() const { return m_space_instance->m_stream; } +int Cuda::cuda_device() const { return m_space_instance->m_cudaDev; } - -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Experimental { -UniqueToken< Kokkos::Cuda , Kokkos::Experimental::UniqueTokenScope::Global >:: -UniqueToken( Kokkos::Cuda const & ) - : m_buffer( Kokkos::Impl::CudaInternal::singleton().m_scratchConcurrentBitset ) - , m_count( Kokkos::Impl::CudaInternal::singleton().m_maxConcurrency ) - {} +UniqueToken:: + UniqueToken(Kokkos::Cuda const &) + : m_buffer( + Kokkos::Impl::CudaInternal::singleton().m_scratchConcurrentBitset), + m_count(Kokkos::Impl::CudaInternal::singleton().m_maxConcurrency) {} -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos #else void KOKKOS_CORE_SRC_CUDA_IMPL_PREVENT_LINK_ERROR() {} -#endif // KOKKOS_ENABLE_CUDA - +#endif // KOKKOS_ENABLE_CUDA diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp index f9e333fcf0..9d2c939af8 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Instance.hpp @@ -3,39 +3,48 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- +// These functions fulfill the purpose of allowing to work around +// a suspected system software issue, or to check for race conditions. +// They are not currently a fully officially supported capability. +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION +extern "C" void kokkos_impl_cuda_set_serial_execution(bool); +extern "C" bool kokkos_impl_cuda_use_serial_execution(); +#endif namespace Kokkos { namespace Impl { struct CudaTraits { - enum { WarpSize = 32 /* 0x0020 */ }; - enum { WarpIndexMask = 0x001f /* Mask for warpindex */ }; - enum { WarpIndexShift = 5 /* WarpSize == 1 << WarpShift */ }; + enum { WarpSize = 32 /* 0x0020 */ }; + enum { WarpIndexMask = 0x001f /* Mask for warpindex */ }; + enum { WarpIndexShift = 5 /* WarpSize == 1 << WarpShift */ }; - enum { ConstantMemoryUsage = 0x008000 /* 32k bytes */ }; - enum { ConstantMemoryCache = 0x002000 /* 8k bytes */ }; - enum { KernelArgumentLimit = 0x001000 /* 4k bytes */ }; + enum { ConstantMemoryUsage = 0x008000 /* 32k bytes */ }; + enum { ConstantMemoryCache = 0x002000 /* 8k bytes */ }; + enum { KernelArgumentLimit = 0x001000 /* 4k bytes */ }; typedef unsigned long - ConstantGlobalBufferType[ ConstantMemoryUsage / sizeof(unsigned long) ]; + ConstantGlobalBufferType[ConstantMemoryUsage / sizeof(unsigned long)]; -#if defined(KOKKOS_ARCH_VOLTA) || \ - defined(KOKKOS_ARCH_PASCAL) - enum { ConstantMemoryUseThreshold = 0x000200 /* 0 bytes -> always use constant (or global)*/ }; +#if defined(KOKKOS_ARCH_VOLTA) || defined(KOKKOS_ARCH_PASCAL) + enum { + ConstantMemoryUseThreshold = + 0x000200 /* 0 bytes -> always use constant (or global)*/ + }; #else enum { ConstantMemoryUseThreshold = 0x000200 /* 512 bytes */ }; #endif - KOKKOS_INLINE_FUNCTION static - CudaSpace::size_type warp_count( CudaSpace::size_type i ) - { return ( i + WarpIndexMask ) >> WarpIndexShift ; } + KOKKOS_INLINE_FUNCTION static CudaSpace::size_type warp_count( + CudaSpace::size_type i) { + return (i + WarpIndexMask) >> WarpIndexShift; + } - KOKKOS_INLINE_FUNCTION static - CudaSpace::size_type warp_align( CudaSpace::size_type i ) - { - enum { Mask = ~CudaSpace::size_type( WarpIndexMask ) }; - return ( i + WarpIndexMask ) & Mask ; - } + KOKKOS_INLINE_FUNCTION static CudaSpace::size_type warp_align( + CudaSpace::size_type i) { + enum { Mask = ~CudaSpace::size_type(WarpIndexMask) }; + return (i + WarpIndexMask) & Mask; + } }; //---------------------------------------------------------------------------- @@ -47,110 +56,118 @@ CudaSpace::size_type cuda_internal_maximum_shared_words(); CudaSpace::size_type cuda_internal_maximum_concurrent_block_count(); -CudaSpace::size_type * cuda_internal_scratch_flags( const Cuda&, const CudaSpace::size_type size ); -CudaSpace::size_type * cuda_internal_scratch_space( const Cuda&, const CudaSpace::size_type size ); -CudaSpace::size_type * cuda_internal_scratch_unified( const Cuda&, const CudaSpace::size_type size ); +CudaSpace::size_type* cuda_internal_scratch_flags( + const Cuda&, const CudaSpace::size_type size); +CudaSpace::size_type* cuda_internal_scratch_space( + const Cuda&, const CudaSpace::size_type size); +CudaSpace::size_type* cuda_internal_scratch_unified( + const Cuda&, const CudaSpace::size_type size); -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { namespace Impl { class CudaInternal { -private: - - CudaInternal( const CudaInternal & ); - CudaInternal & operator = ( const CudaInternal & ); - - -public: + private: + CudaInternal(const CudaInternal&); + CudaInternal& operator=(const CudaInternal&); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + static bool kokkos_impl_cuda_use_serial_execution_v; +#endif - typedef Cuda::size_type size_type ; + public: + typedef Cuda::size_type size_type; - int m_cudaDev ; + int m_cudaDev; // Device Properties - int m_cudaArch ; - unsigned m_multiProcCount ; - unsigned m_maxWarpCount ; - unsigned m_maxBlock ; - unsigned m_maxSharedWords ; - uint32_t m_maxConcurrency ; - int m_shmemPerSM ; - int m_maxShmemPerBlock ; - int m_regsPerSM ; - int m_maxBlocksPerSM ; - int m_maxThreadsPerSM ; - int m_maxThreadsPerBlock ; - - mutable size_type m_scratchSpaceCount ; - mutable size_type m_scratchFlagsCount ; - mutable size_type m_scratchUnifiedCount ; - mutable size_type m_scratchFunctorSize ; - size_type m_scratchUnifiedSupported ; - size_type m_streamCount ; - mutable size_type * m_scratchSpace ; - mutable size_type * m_scratchFlags ; - mutable size_type * m_scratchUnified ; - mutable size_type * m_scratchFunctor ; - uint32_t * m_scratchConcurrentBitset ; - cudaStream_t m_stream ; + int m_cudaArch; + unsigned m_multiProcCount; + unsigned m_maxWarpCount; + unsigned m_maxBlock; + unsigned m_maxSharedWords; + uint32_t m_maxConcurrency; + int m_shmemPerSM; + int m_maxShmemPerBlock; + int m_regsPerSM; + int m_maxBlocksPerSM; + int m_maxThreadsPerSM; + int m_maxThreadsPerBlock; + + mutable size_type m_scratchSpaceCount; + mutable size_type m_scratchFlagsCount; + mutable size_type m_scratchUnifiedCount; + mutable size_type m_scratchFunctorSize; + size_type m_scratchUnifiedSupported; + size_type m_streamCount; + mutable size_type* m_scratchSpace; + mutable size_type* m_scratchFlags; + mutable size_type* m_scratchUnified; + mutable size_type* m_scratchFunctor; + uint32_t* m_scratchConcurrentBitset; + cudaStream_t m_stream; static int was_initialized; static int was_finalized; - static CudaInternal & singleton(); + static CudaInternal& singleton(); - int verify_is_initialized( const char * const label ) const ; + int verify_is_initialized(const char* const label) const; - int is_initialized() const - { return 0 != m_scratchSpace && 0 != m_scratchFlags ; } + int is_initialized() const { + return 0 != m_scratchSpace && 0 != m_scratchFlags; + } - void initialize( int cuda_device_id , cudaStream_t stream = 0 ); + void initialize(int cuda_device_id, cudaStream_t stream = 0); void finalize(); - void print_configuration( std::ostream & ) const ; + void print_configuration(std::ostream&) const; + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + static bool cuda_use_serial_execution(); + static void cuda_set_serial_execution(bool); +#endif - void fence() const ; + void fence() const; ~CudaInternal(); CudaInternal() - : m_cudaDev( -1 ) - , m_cudaArch( -1 ) - , m_multiProcCount( 0 ) - , m_maxWarpCount( 0 ) - , m_maxBlock( 0 ) - , m_maxSharedWords( 0 ) - , m_maxConcurrency( 0 ) - , m_shmemPerSM( 0 ) - , m_maxShmemPerBlock( 0 ) - , m_regsPerSM( 0 ) - , m_maxBlocksPerSM( 0 ) - , m_maxThreadsPerSM( 0 ) - , m_maxThreadsPerBlock( 0 ) - , m_scratchSpaceCount( 0 ) - , m_scratchFlagsCount( 0 ) - , m_scratchUnifiedCount( 0 ) - , m_scratchFunctorSize( 0 ) - , m_scratchUnifiedSupported( 0 ) - , m_streamCount( 0 ) - , m_scratchSpace( 0 ) - , m_scratchFlags( 0 ) - , m_scratchUnified( 0 ) - , m_scratchFunctor( 0 ) - , m_scratchConcurrentBitset( 0 ) - , m_stream( 0 ) - {} - - size_type * scratch_space( const size_type size ) const ; - size_type * scratch_flags( const size_type size ) const ; - size_type * scratch_unified( const size_type size ) const ; - size_type * scratch_functor( const size_type size ) const ; + : m_cudaDev(-1), + m_cudaArch(-1), + m_multiProcCount(0), + m_maxWarpCount(0), + m_maxBlock(0), + m_maxSharedWords(0), + m_maxConcurrency(0), + m_shmemPerSM(0), + m_maxShmemPerBlock(0), + m_regsPerSM(0), + m_maxBlocksPerSM(0), + m_maxThreadsPerSM(0), + m_maxThreadsPerBlock(0), + m_scratchSpaceCount(0), + m_scratchFlagsCount(0), + m_scratchUnifiedCount(0), + m_scratchFunctorSize(0), + m_scratchUnifiedSupported(0), + m_streamCount(0), + m_scratchSpace(0), + m_scratchFlags(0), + m_scratchUnified(0), + m_scratchFunctor(0), + m_scratchConcurrentBitset(0), + m_stream(0) {} + + size_type* scratch_space(const size_type size) const; + size_type* scratch_flags(const size_type size) const; + size_type* scratch_unified(const size_type size) const; + size_type* scratch_functor(const size_type size) const; }; -} // Namespace Impl -} // Namespace Kokkos +} // Namespace Impl +} // Namespace Kokkos #endif diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp index 2ec868c1f1..590fa7a784 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_KernelLaunch.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -59,32 +60,32 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -#if defined( __CUDACC__ ) +#if defined(__CUDACC__) /** \brief Access to constant memory on the device */ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -__device__ __constant__ -extern unsigned long kokkos_impl_cuda_constant_memory_buffer[] ; +__device__ __constant__ extern unsigned long + kokkos_impl_cuda_constant_memory_buffer[]; #else -__device__ __constant__ -unsigned long kokkos_impl_cuda_constant_memory_buffer[ Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long) ] ; +__device__ __constant__ unsigned long kokkos_impl_cuda_constant_memory_buffer + [Kokkos::Impl::CudaTraits::ConstantMemoryUsage / sizeof(unsigned long)]; #endif namespace Kokkos { namespace Impl { - void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink = false); -} +void* cuda_resize_scratch_space(std::int64_t bytes, bool force_shrink = false); } +} // namespace Kokkos -template< typename T > -inline -__device__ -T * kokkos_impl_cuda_shared_memory() -{ extern __shared__ Kokkos::CudaSpace::size_type sh[]; return (T*) sh ; } +template +inline __device__ T* kokkos_impl_cuda_shared_memory() { + extern __shared__ Kokkos::CudaSpace::size_type sh[]; + return (T*)sh; +} namespace Kokkos { namespace Impl { @@ -100,105 +101,111 @@ namespace Impl { // For 2.0 capability: 48 KB L1 and 16 KB shared //---------------------------------------------------------------------------- -template< class DriverType> -__global__ -static void cuda_parallel_launch_constant_memory() -{ - const DriverType & driver = - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +template +__global__ static void cuda_parallel_launch_constant_memory() { + const DriverType& driver = + *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > -__global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_constant_memory() -{ - const DriverType & driver = - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +template +__global__ __launch_bounds__( + maxTperB, minBperSM) static void cuda_parallel_launch_constant_memory() { + const DriverType& driver = + *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType> -__global__ -static void cuda_parallel_launch_local_memory( const DriverType driver ) -{ +template +__global__ static void cuda_parallel_launch_local_memory( + const DriverType driver) { driver(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > -__global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_local_memory( const DriverType driver ) -{ +template +__global__ __launch_bounds__( + maxTperB, + minBperSM) static void cuda_parallel_launch_local_memory(const DriverType + driver) { driver(); } -template< class DriverType> -__global__ -static void cuda_parallel_launch_global_memory( const DriverType* driver ) -{ +template +__global__ static void cuda_parallel_launch_global_memory( + const DriverType* driver) { driver->operator()(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > -__global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_global_memory( const DriverType* driver ) -{ +template +__global__ __launch_bounds__( + maxTperB, + minBperSM) static void cuda_parallel_launch_global_memory(const DriverType* + driver) { driver->operator()(); } -template< class DriverType> -__global__ -static void cuda_parallel_launch_constant_or_global_memory( const DriverType* driver_ptr ) -{ - const DriverType & driver = driver_ptr!=NULL ? *driver_ptr : - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +template +__global__ static void cuda_parallel_launch_constant_or_global_memory( + const DriverType* driver_ptr) { + const DriverType& driver = + driver_ptr != NULL + ? *driver_ptr + : *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType, unsigned int maxTperB, unsigned int minBperSM > +template __global__ -__launch_bounds__(maxTperB, minBperSM) -static void cuda_parallel_launch_constant_or_global_memory( const DriverType* driver_ptr ) -{ - const DriverType & driver = driver_ptr!=NULL ? *driver_ptr : - *((const DriverType *) kokkos_impl_cuda_constant_memory_buffer ); +__launch_bounds__(maxTperB, minBperSM) static void cuda_parallel_launch_constant_or_global_memory( + const DriverType* driver_ptr) { + const DriverType& driver = + driver_ptr != NULL + ? *driver_ptr + : *((const DriverType*)kokkos_impl_cuda_constant_memory_buffer); driver(); } -template< class DriverType > +template struct DeduceCudaLaunchMechanism { - constexpr static const Kokkos::Experimental::WorkItemProperty::HintLightWeight_t light_weight = Kokkos::Experimental::WorkItemProperty::HintLightWeight; - constexpr static const Kokkos::Experimental::WorkItemProperty::HintHeavyWeight_t heavy_weight = Kokkos::Experimental::WorkItemProperty::HintHeavyWeight ; - constexpr static const typename DriverType::Policy::work_item_property property = typename DriverType::Policy::work_item_property(); - - static constexpr const Experimental::CudaLaunchMechanism valid_launch_mechanism = - // BuildValidMask - (sizeof(DriverType) - , Experimental::CudaLaunchMechanism LaunchMechanism = - DeduceCudaLaunchMechanism::launch_mechanism > -struct CudaParallelLaunch ; - -template < class DriverType - , unsigned int MaxThreadsPerBlock - , unsigned int MinBlocksPerSM> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds< MaxThreadsPerBlock - , MinBlocksPerSM > - , Experimental::CudaLaunchMechanism::ConstantMemory> -{ - static_assert(sizeof(DriverType), + Experimental::CudaLaunchMechanism LaunchMechanism = + DeduceCudaLaunchMechanism::launch_mechanism> +struct CudaParallelLaunch; + +template +struct CudaParallelLaunch< + DriverType, Kokkos::LaunchBounds, + Experimental::CudaLaunchMechanism::ConstantMemory> { + static_assert(sizeof(DriverType) < CudaTraits::ConstantMemoryUsage, + "Kokkos Error: Requested CudaLaunchConstantMemory with a " + "Functor larger than 32kB."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { // Fence before changing settings and copying closure Kokkos::Cuda().fence(); - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_constant_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_constant_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif // Copy functor to constant memory on the device - cudaMemcpyToSymbolAsync( - kokkos_impl_cuda_constant_memory_buffer, &driver, sizeof(DriverType), 0, cudaMemcpyHostToDevice, cudaStream_t(cuda_instance->m_stream)); + cudaMemcpyToSymbolAsync(kokkos_impl_cuda_constant_memory_buffer, &driver, + sizeof(DriverType), 0, cudaMemcpyHostToDevice, + cudaStream_t(cuda_instance->m_stream)); KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_constant_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - <<< grid , block , shmem , cuda_instance->m_stream >>>(); + cuda_parallel_launch_constant_memory + <<m_stream>>>(); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -283,57 +283,55 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_constant_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, + cuda_parallel_launch_constant_memory)); return attr; } }; -template < class DriverType> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds<0,0> - , Experimental::CudaLaunchMechanism::ConstantMemory > -{ - static_assert(sizeof(DriverType) +struct CudaParallelLaunch, + Experimental::CudaLaunchMechanism::ConstantMemory> { + static_assert(sizeof(DriverType) < CudaTraits::ConstantMemoryUsage, + "Kokkos Error: Requested CudaLaunchConstantMemory with a " + "Functor larger than 32kB."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { // Fence before changing settings and copying closure Kokkos::Cuda().fence(); - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_constant_memory< DriverType > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_constant_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif // Copy functor to constant memory on the device - cudaMemcpyToSymbolAsync( - kokkos_impl_cuda_constant_memory_buffer, &driver, sizeof(DriverType), 0, cudaMemcpyHostToDevice, cudaStream_t(cuda_instance->m_stream)); + cudaMemcpyToSymbolAsync(kokkos_impl_cuda_constant_memory_buffer, &driver, + sizeof(DriverType), 0, cudaMemcpyHostToDevice, + cudaStream_t(cuda_instance->m_stream)); KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_constant_memory< DriverType > - <<< grid , block , shmem , cuda_instance->m_stream >>>(); + cuda_parallel_launch_constant_memory + <<m_stream>>>(); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -341,55 +339,49 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_constant_memory - < DriverType >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_constant_memory)); return attr; } }; -template < class DriverType - , unsigned int MaxThreadsPerBlock - , unsigned int MinBlocksPerSM > -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds< MaxThreadsPerBlock - , MinBlocksPerSM > - , Experimental::CudaLaunchMechanism::LocalMemory > -{ - static_assert(sizeof(DriverType)m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch< + DriverType, Kokkos::LaunchBounds, + Experimental::CudaLaunchMechanism::LocalMemory> { + static_assert(sizeof(DriverType) < CudaTraits::KernelArgumentLimit, + "Kokkos Error: Requested CudaLaunchLocalMemory with a Functor " + "larger than 4096 bytes."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_local_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_local_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_local_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver ); + cuda_parallel_launch_local_memory + <<m_stream>>>(driver); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -397,50 +389,46 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_local_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_local_memory)); return attr; } }; -template < class DriverType> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds<0,0> - , Experimental::CudaLaunchMechanism::LocalMemory > -{ - static_assert(sizeof(DriverType)m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch, + Experimental::CudaLaunchMechanism::LocalMemory> { + static_assert(sizeof(DriverType) < CudaTraits::KernelArgumentLimit, + "Kokkos Error: Requested CudaLaunchLocalMemory with a Functor " + "larger than 4096 bytes."); + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + const CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_local_memory< DriverType > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_local_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); // Invoke the driver function on the device - cuda_parallel_launch_local_memory< DriverType > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver ); + cuda_parallel_launch_local_memory + <<m_stream>>>(driver); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -448,111 +436,101 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_local_memory - < DriverType >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_local_memory)); return attr; } }; -template < class DriverType - , unsigned int MaxThreadsPerBlock - , unsigned int MinBlocksPerSM> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds< MaxThreadsPerBlock - , MinBlocksPerSM> - , Experimental::CudaLaunchMechanism::GlobalMemory > -{ - inline - CudaParallelLaunch( const DriverType & driver - , const dim3 & grid - , const dim3 & block - , const int shmem - , CudaInternal* cuda_instance - , const bool prefer_shmem ) - { - if ( (grid.x != 0) && ( ( block.x * block.y * block.z ) != 0 ) ) { - - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch< + DriverType, Kokkos::LaunchBounds, + Experimental::CudaLaunchMechanism::GlobalMemory> { + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_global_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_global_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); DriverType* driver_ptr = NULL; - driver_ptr = reinterpret_cast(cuda_instance->scratch_functor(sizeof(DriverType))); - cudaMemcpyAsync(driver_ptr,&driver, sizeof(DriverType), cudaMemcpyDefault, cuda_instance->m_stream); + driver_ptr = reinterpret_cast( + cuda_instance->scratch_functor(sizeof(DriverType))); + cudaMemcpyAsync(driver_ptr, &driver, sizeof(DriverType), + cudaMemcpyDefault, cuda_instance->m_stream); // Invoke the driver function on the device - cuda_parallel_launch_global_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver_ptr ); + cuda_parallel_launch_global_memory + <<m_stream>>>(driver_ptr); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } } static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_global_memory - < DriverType, MaxThreadsPerBlock, MinBlocksPerSM >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, + cuda_parallel_launch_global_memory)); return attr; } - }; -template < class DriverType> -struct CudaParallelLaunch< DriverType - , Kokkos::LaunchBounds<0,0> - , Experimental::CudaLaunchMechanism::GlobalMemory > -{ - inline - CudaParallelLaunch( const DriverType & driver - , const dim3 & grid - , const dim3 & block - , const int shmem - , CudaInternal* cuda_instance - , const bool prefer_shmem) - { - if ( (grid.x != 0) && ( ( block.x * block.y * block.z ) != 0 ) ) { - - if ( cuda_instance->m_maxShmemPerBlock < shmem ) { - Kokkos::Impl::throw_runtime_exception( std::string("CudaParallelLaunch FAILED: shared memory request is too large") ); +template +struct CudaParallelLaunch, + Experimental::CudaLaunchMechanism::GlobalMemory> { + inline CudaParallelLaunch(const DriverType& driver, const dim3& grid, + const dim3& block, const int shmem, + CudaInternal* cuda_instance, + const bool prefer_shmem) { + if ((grid.x != 0) && ((block.x * block.y * block.z) != 0)) { + if (cuda_instance->m_maxShmemPerBlock < shmem) { + Kokkos::Impl::throw_runtime_exception(std::string( + "CudaParallelLaunch FAILED: shared memory request is too large")); } - #ifndef KOKKOS_ARCH_KEPLER +#ifndef KOKKOS_ARCH_KEPLER // On Kepler the L1 has no benefit since it doesn't cache reads else { - CUDA_SAFE_CALL( - cudaFuncSetCacheConfig - ( cuda_parallel_launch_global_memory< DriverType > - , ( prefer_shmem ? cudaFuncCachePreferShared : cudaFuncCachePreferL1 ) - ) ); + CUDA_SAFE_CALL(cudaFuncSetCacheConfig( + cuda_parallel_launch_global_memory, + (prefer_shmem ? cudaFuncCachePreferShared + : cudaFuncCachePreferL1))); } - #endif +#endif KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE(); DriverType* driver_ptr = NULL; - driver_ptr = reinterpret_cast(cuda_instance->scratch_functor(sizeof(DriverType))); - cudaMemcpyAsync(driver_ptr,&driver, sizeof(DriverType), cudaMemcpyDefault, cuda_instance->m_stream); + driver_ptr = reinterpret_cast( + cuda_instance->scratch_functor(sizeof(DriverType))); + cudaMemcpyAsync(driver_ptr, &driver, sizeof(DriverType), + cudaMemcpyDefault, cuda_instance->m_stream); - cuda_parallel_launch_global_memory< DriverType > - <<< grid , block , shmem , cuda_instance->m_stream >>>( driver_ptr ); + cuda_parallel_launch_global_memory + <<m_stream>>>(driver_ptr); -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) - CUDA_SAFE_CALL( cudaGetLastError() ); +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) + CUDA_SAFE_CALL(cudaGetLastError()); Kokkos::Cuda().fence(); #endif } @@ -560,15 +538,15 @@ struct CudaParallelLaunch< DriverType static cudaFuncAttributes get_cuda_func_attributes() { cudaFuncAttributes attr; - cudaFuncGetAttributes(&attr,cuda_parallel_launch_global_memory - < DriverType >); + CUDA_SAFE_CALL(cudaFuncGetAttributes( + &attr, cuda_parallel_launch_global_memory)); return attr; } }; //---------------------------------------------------------------------------- -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -576,4 +554,3 @@ struct CudaParallelLaunch< DriverType #endif /* defined( __CUDACC__ ) */ #endif /* defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDAEXEC_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp index f1828ea2de..07dadb3c16 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,10 +53,10 @@ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE namespace Kokkos { namespace Impl { -__device__ __constant__ -CudaLockArrays g_device_cuda_lock_arrays = { nullptr, nullptr, 0 }; -} +__device__ __constant__ CudaLockArrays g_device_cuda_lock_arrays = {nullptr, + nullptr, 0}; } +} // namespace Kokkos #endif namespace Kokkos { @@ -63,36 +64,38 @@ namespace Kokkos { namespace { __global__ void init_lock_array_kernel_atomic() { - unsigned i = blockIdx.x*blockDim.x + threadIdx.x; - if(i>>(); - init_lock_array_kernel_threadid<<<(Kokkos::Cuda::concurrency()+255)/256,256>>>(Kokkos::Cuda::concurrency()); + init_lock_array_kernel_atomic<<<(CUDA_SPACE_ATOMIC_MASK + 1 + 255) / 256, + 256>>>(); + init_lock_array_kernel_threadid<<<(Kokkos::Cuda::concurrency() + 255) / 256, + 256>>>(Kokkos::Cuda::concurrency()); CUDA_SAFE_CALL(cudaDeviceSynchronize()); } @@ -102,15 +105,15 @@ void finalize_host_cuda_lock_arrays() { g_host_cuda_lock_arrays.atomic = nullptr; cudaFree(g_host_cuda_lock_arrays.scratch); g_host_cuda_lock_arrays.scratch = nullptr; - g_host_cuda_lock_arrays.n = 0; + g_host_cuda_lock_arrays.n = 0; #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE(); #endif } -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos #else diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp index cfc46f0461..84a9c3821e 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Locks.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,7 +64,7 @@ struct CudaLockArrays { /// \brief This global variable in Host space is the central definition /// of these arrays. -extern Kokkos::Impl::CudaLockArrays g_host_cuda_lock_arrays ; +extern Kokkos::Impl::CudaLockArrays g_host_cuda_lock_arrays; /// \brief After this call, the g_host_cuda_lock_arrays variable has /// valid, initialized arrays. @@ -77,10 +78,10 @@ void initialize_host_cuda_lock_arrays(); /// This call is idempotent. void finalize_host_cuda_lock_arrays(); -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos -#if defined( __CUDACC__ ) +#if defined(__CUDACC__) namespace Kokkos { namespace Impl { @@ -106,73 +107,70 @@ namespace Impl { /// That is the purpose of the KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE macro. __device__ #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE -__constant__ -extern + __constant__ extern #endif -Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays ; + Kokkos::Impl::CudaLockArrays g_device_cuda_lock_arrays; #define CUDA_SPACE_ATOMIC_MASK 0x1FFFF -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. -__device__ inline -bool lock_address_cuda_space(void* ptr) { +__device__ inline bool lock_address_cuda_space(void* ptr) { size_t offset = size_t(ptr); - offset = offset >> 2; - offset = offset & CUDA_SPACE_ATOMIC_MASK; - return (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset],0,1)); + offset = offset >> 2; + offset = offset & CUDA_SPACE_ATOMIC_MASK; + return ( + 0 == + atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset], 0, 1)); } /// \brief Release lock for the address /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -__device__ inline -void unlock_address_cuda_space(void* ptr) { +__device__ inline void unlock_address_cuda_space(void* ptr) { size_t offset = size_t(ptr); - offset = offset >> 2; - offset = offset & CUDA_SPACE_ATOMIC_MASK; - atomicExch( &Kokkos::Impl::g_device_cuda_lock_arrays.atomic[ offset ], 0); + offset = offset >> 2; + offset = offset & CUDA_SPACE_ATOMIC_MASK; + atomicExch(&Kokkos::Impl::g_device_cuda_lock_arrays.atomic[offset], 0); } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos // Make lock_array_copied an explicit translation unit scope thingy namespace Kokkos { namespace Impl { namespace { - static int lock_array_copied = 0; - inline int eliminate_warning_for_lock_array() { - return lock_array_copied; - } -} -} -} +static int lock_array_copied = 0; +inline int eliminate_warning_for_lock_array() { return lock_array_copied; } +} // namespace +} // namespace Impl +} // namespace Kokkos /* Dan Ibanez: it is critical that this code be a macro, so that it will capture the right address for Kokkos::Impl::g_device_cuda_lock_arrays! putting this in an inline function will NOT do the right thing! */ -#define KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ -{ \ - if(::Kokkos::Impl::lock_array_copied == 0) { \ - CUDA_SAFE_CALL(cudaMemcpyToSymbol( \ - Kokkos::Impl::g_device_cuda_lock_arrays , \ - & Kokkos::Impl::g_host_cuda_lock_arrays , \ - sizeof(Kokkos::Impl::CudaLockArrays) ) ); \ - } \ - lock_array_copied = 1; \ - \ -} +#define KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() \ + { \ + if (::Kokkos::Impl::lock_array_copied == 0) { \ + CUDA_SAFE_CALL( \ + cudaMemcpyToSymbol(Kokkos::Impl::g_device_cuda_lock_arrays, \ + &Kokkos::Impl::g_host_cuda_lock_arrays, \ + sizeof(Kokkos::Impl::CudaLockArrays))); \ + } \ + lock_array_copied = 1; \ + } #ifdef KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE #define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() #else -#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() +#define KOKKOS_ENSURE_CUDA_LOCK_ARRAYS_ON_DEVICE() \ + KOKKOS_COPY_CUDA_LOCK_ARRAYS_TO_DEVICE() #endif #endif /* defined( __CUDACC__ ) */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp index 860d94d6c7..4c5fe4b7f1 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Parallel.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_PARALLEL_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -78,202 +79,223 @@ extern bool show_warnings() noexcept; namespace Impl { -template< class ... Properties > -class TeamPolicyInternal< Kokkos::Cuda , Properties ... >: public PolicyTraits -{ -public: - +template +class TeamPolicyInternal + : public PolicyTraits { + public: //! Tag this class as a kokkos execution policy - typedef TeamPolicyInternal execution_policy ; + typedef TeamPolicyInternal execution_policy; - typedef PolicyTraits traits; + typedef PolicyTraits traits; - template< class ExecSpace, class ... OtherProperties > + template friend class TeamPolicyInternal; -private: - + private: enum { MAX_WARP = 8 }; typename traits::execution_space m_space; - int m_league_size ; - int m_team_size ; - int m_vector_length ; - int m_team_scratch_size[2] ; - int m_thread_scratch_size[2] ; + int m_league_size; + int m_team_size; + int m_vector_length; + int m_team_scratch_size[2]; + int m_thread_scratch_size[2]; int m_chunk_size; -public: - + public: //! Execution space of this execution policy - typedef Kokkos::Cuda execution_space ; - - template - TeamPolicyInternal( const TeamPolicyInternal& p ) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_vector_length = p.m_vector_length; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + typedef Kokkos::Cuda execution_space; + + template + TeamPolicyInternal(const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_vector_length = p.m_vector_length; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; - m_space = p.m_space; + m_chunk_size = p.m_chunk_size; + m_space = p.m_space; } - TeamPolicyInternal& operator = (const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_vector_length = p.m_vector_length; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + TeamPolicyInternal& operator=(const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_vector_length = p.m_vector_length; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; - m_space = p.m_space; + m_chunk_size = p.m_chunk_size; + m_space = p.m_space; return *this; } //---------------------------------------- #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class FunctorType > - static inline - int team_size_max( const FunctorType & functor ) - { - int n = MAX_WARP * Impl::CudaTraits::WarpSize ; - - for ( ; n ; n >>= 1 ) { - const int shmem_size = - /* for global reduce */ Impl::cuda_single_inter_block_reduce_scan_shmem( functor , n ) - /* for team reduce */ + ( n + 2 ) * sizeof(double) - /* for team shared */ + Impl::FunctorTeamShmemSize< FunctorType >::value( functor , n ); - - if ( shmem_size < typename traits::execution_space().impl_internal_space_instance()->m_maxShmemPerBlock ) break ; - } - - return n ; - } + template + static inline int team_size_max(const FunctorType& functor) { + int n = MAX_WARP * Impl::CudaTraits::WarpSize; + + for (; n; n >>= 1) { + const int shmem_size = + /* for global reduce */ Impl:: + cuda_single_inter_block_reduce_scan_shmem< + false, FunctorType, typename traits::work_tag>(functor, n) + /* for team reduce */ + + (n + 2) * sizeof(double) + /* for team shared */ + + Impl::FunctorTeamShmemSize::value(functor, n); + + if (shmem_size < typename traits::execution_space() + .impl_internal_space_instance() + ->m_maxShmemPerBlock) + break; + } + + return n; + } #endif - template - int team_size_max( const FunctorType& f, const ParallelForTag& ) const { - typedef Impl::ParallelFor< FunctorType , TeamPolicy > closure_type; - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - int block_size = Kokkos::Impl::cuda_get_max_block_size< FunctorType, typename traits::launch_bounds >( - space().impl_internal_space_instance(),attr,f ,(size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double) ); - return block_size/vector_length(); - } - - template - int team_size_max( const FunctorType& f, const ParallelReduceTag& ) const { - typedef Impl::FunctorAnalysis functor_analysis_type; - typedef typename Impl::ParallelReduceReturnValue::reducer_type reducer_type; - typedef Impl::ParallelReduce< FunctorType , TeamPolicy, reducer_type > closure_type; - typedef Impl::FunctorValueTraits< FunctorType , typename traits::work_tag > functor_value_traits; - - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - int block_size = Kokkos::Impl::cuda_get_max_block_size< FunctorType, typename traits::launch_bounds >( - space().impl_internal_space_instance(),attr,f ,(size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double) + - ((functor_value_traits::StaticValueSize!=0)?0:functor_value_traits::value_size( f ))); + template + int team_size_max(const FunctorType& f, const ParallelForTag&) const { + typedef Impl::ParallelFor> + closure_type; + cudaFuncAttributes attr = + CudaParallelLaunch:: + get_cuda_func_attributes(); + int block_size = + Kokkos::Impl::cuda_get_max_block_size( + space().impl_internal_space_instance(), attr, f, + (size_t)vector_length(), + (size_t)team_scratch_size(0) + 2 * sizeof(double), + (size_t)thread_scratch_size(0) + sizeof(double)); + return block_size / vector_length(); + } - // Currently we require Power-of-2 team size for reductions. - int p2 = 1; - while(p2<=block_size) p2*=2; - p2/=2; - return p2/vector_length(); + template + inline int team_size_max(const FunctorType& f, + const ParallelReduceTag&) const { + typedef Impl::FunctorAnalysis + functor_analysis_type; + typedef typename Impl::ParallelReduceReturnValue< + void, typename functor_analysis_type::value_type, + FunctorType>::reducer_type reducer_type; + typedef Impl::ParallelReduce, + reducer_type> + closure_type; + return internal_team_size_max(f); + } + + template + inline int team_size_max(const FunctorType& f, const ReducerType& r, + const ParallelReduceTag&) const { + using closure_type = + Impl::ParallelReduce, + ReducerType>; + return internal_team_size_max(f); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class FunctorType > - static int team_size_recommended( const FunctorType & functor ) - { return team_size_max( functor ); } + template + static int team_size_recommended(const FunctorType& functor) { + return team_size_max(functor); + } - template< class FunctorType > - static int team_size_recommended( const FunctorType & functor , const int vector_length) - { - int max = team_size_max( functor )/vector_length; - if(max<1) max = 1; - return max; - } + template + static int team_size_recommended(const FunctorType& functor, + const int vector_length) { + int max = team_size_max(functor) / vector_length; + if (max < 1) max = 1; + return max; + } #endif - template - int team_size_recommended( const FunctorType& f, const ParallelForTag& ) const { - typedef Impl::ParallelFor< FunctorType , TeamPolicy > closure_type; - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - const int block_size = Kokkos::Impl::cuda_get_opt_block_size< FunctorType, typename traits::launch_bounds>( - space().impl_internal_space_instance(), - attr, f , (size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double)); - return block_size/vector_length(); - } - - template - int team_size_recommended( const FunctorType& f, const ParallelReduceTag& ) const { - typedef Impl::FunctorAnalysis functor_analysis_type; - typedef typename Impl::ParallelReduceReturnValue::reducer_type reducer_type; - typedef Impl::ParallelReduce< FunctorType , TeamPolicy, reducer_type > closure_type; - typedef Impl::FunctorValueTraits< FunctorType , typename traits::work_tag > functor_value_traits; - - cudaFuncAttributes attr = CudaParallelLaunch< closure_type, typename traits::launch_bounds >:: - get_cuda_func_attributes(); - const int block_size = Kokkos::Impl::cuda_get_opt_block_size< FunctorType, typename traits::launch_bounds>( - space().impl_internal_space_instance(), - attr, f , (size_t) vector_length(), - (size_t) team_scratch_size(0) + 2*sizeof(double), (size_t) thread_scratch_size(0) + sizeof(double) + - ((functor_value_traits::StaticValueSize!=0)?0:functor_value_traits::value_size( f ))); - // Currently we require Power-of-2 team size for reductions. - int p2 = 1; - while(p2<=block_size) p2*=2; - p2/=2; - return p2/vector_length(); + template + int team_size_recommended(const FunctorType& f, const ParallelForTag&) const { + typedef Impl::ParallelFor> + closure_type; + cudaFuncAttributes attr = + CudaParallelLaunch:: + get_cuda_func_attributes(); + const int block_size = + Kokkos::Impl::cuda_get_opt_block_size( + space().impl_internal_space_instance(), attr, f, + (size_t)vector_length(), + (size_t)team_scratch_size(0) + 2 * sizeof(double), + (size_t)thread_scratch_size(0) + sizeof(double)); + return block_size / vector_length(); } + template + inline int team_size_recommended(const FunctorType& f, + const ParallelReduceTag&) const { + typedef Impl::FunctorAnalysis + functor_analysis_type; + typedef typename Impl::ParallelReduceReturnValue< + void, typename functor_analysis_type::value_type, + FunctorType>::reducer_type reducer_type; + typedef Impl::ParallelReduce, + reducer_type> + closure_type; + return internal_team_size_recommended(f); + } - inline static - int vector_length_max() - { return Impl::CudaTraits::WarpSize; } + template + int team_size_recommended(const FunctorType& f, const ReducerType&, + const ParallelReduceTag&) const { + typedef Impl::ParallelReduce, + ReducerType> + closure_type; + return internal_team_size_recommended(f); + } - inline static - int verify_requested_vector_length( int requested_vector_length ) { - int test_vector_length = std::min( requested_vector_length, vector_length_max() ); + inline static int vector_length_max() { return Impl::CudaTraits::WarpSize; } - // Allow only power-of-two vector_length - if ( !(is_integral_power_of_two( test_vector_length ) ) ) { - int test_pow2 = 1; - for (int i = 0; i < 5; i++) { - test_pow2 = test_pow2 << 1; - if (test_pow2 > test_vector_length) { - break; - } - } - test_vector_length = test_pow2 >> 1; + inline static int verify_requested_vector_length( + int requested_vector_length) { + int test_vector_length = + std::min(requested_vector_length, vector_length_max()); + + // Allow only power-of-two vector_length + if (!(is_integral_power_of_two(test_vector_length))) { + int test_pow2 = 1; + for (int i = 0; i < 5; i++) { + test_pow2 = test_pow2 << 1; + if (test_pow2 > test_vector_length) { + break; + } } + test_vector_length = test_pow2 >> 1; + } - return test_vector_length; + return test_vector_length; } - inline static - int scratch_size_max(int level) - { return (level==0? - 1024*40: // 48kB is the max for CUDA, but we need some for team_member.reduce etc. - 20*1024*1024); // arbitrarily setting this to 20MB, for a Volta V100 that would give us about 3.2GB for 2 teams per SM - } + inline static int scratch_size_max(int level) { + return ( + level == 0 ? 1024 * 40 : // 48kB is the max for CUDA, but we need some + // for team_member.reduce etc. + 20 * 1024 * + 1024); // arbitrarily setting this to 20MB, for a Volta V100 + // that would give us about 3.2GB for 2 teams per SM + } //---------------------------------------- - inline int vector_length() const { return m_vector_length ; } - inline int team_size() const { return m_team_size ; } - inline int league_size() const { return m_league_size ; } + inline int vector_length() const { return m_vector_length; } + inline int team_size() const { return m_team_size; } + inline int league_size() const { return m_league_size; } inline int scratch_size(int level, int team_size_ = -1) const { - if(team_size_<0) team_size_ = m_team_size; - return m_team_scratch_size[level] + team_size_*m_thread_scratch_size[level]; + if (team_size_ < 0) team_size_ = m_team_size; + return m_team_scratch_size[level] + + team_size_ * m_thread_scratch_size[level]; } inline int team_scratch_size(int level) const { return m_team_scratch_size[level]; @@ -282,189 +304,259 @@ public: return m_thread_scratch_size[level]; } - inline typename traits::execution_space space() const { - return m_space; - } + inline typename traits::execution_space space() const { return m_space; } TeamPolicyInternal() - : m_space(typename traits::execution_space()) - , m_league_size( 0 ) - , m_team_size( -1 ) - , m_vector_length( 0 ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - {} + : m_space(typename traits::execution_space()), + m_league_size(0), + m_team_size(-1), + m_vector_length(0), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) {} /** \brief Specify league size, request team size */ - TeamPolicyInternal( const execution_space space_ - , int league_size_ - , int team_size_request - , int vector_length_request = 1 ) - : m_space( space_ ) - , m_league_size( league_size_ ) - , m_team_size( team_size_request ) - , m_vector_length( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - - // Make sure total block size is permissible - if ( m_team_size * m_vector_length > 1024 ) { - Impl::throw_runtime_exception(std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. Team size x vector length must be smaller than 1024.")); - } + TeamPolicyInternal(const execution_space space_, int league_size_, + int team_size_request, int vector_length_request = 1) + : m_space(space_), + m_league_size(league_size_), + m_team_size(team_size_request), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + + // Make sure total block size is permissable + if (m_team_size * m_vector_length > 1024) { + Impl::throw_runtime_exception( + std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. " + "Team size x vector length must be smaller than 1024.")); } + } /** \brief Specify league size, request team size */ - TeamPolicyInternal( const execution_space space_ - , int league_size_ - , const Kokkos::AUTO_t & /* team_size_request */ - , int vector_length_request = 1 ) - : m_space( space_ ) - , m_league_size( league_size_ ) - , m_team_size( -1 ) - , m_vector_length( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - } - - TeamPolicyInternal( int league_size_ - , int team_size_request - , int vector_length_request = 1 ) - : m_space( typename traits::execution_space() ) - , m_league_size( league_size_ ) - , m_team_size( team_size_request ) - , m_vector_length ( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); + TeamPolicyInternal(const execution_space space_, int league_size_, + const Kokkos::AUTO_t& /* team_size_request */ + , + int vector_length_request = 1) + : m_space(space_), + m_league_size(league_size_), + m_team_size(-1), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + } - // Make sure total block size is permissible - if ( m_team_size * m_vector_length > 1024 ) { - Impl::throw_runtime_exception(std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. Team size x vector length must be smaller than 1024.")); - } + TeamPolicyInternal(int league_size_, int team_size_request, + int vector_length_request = 1) + : m_space(typename traits::execution_space()), + m_league_size(league_size_), + m_team_size(team_size_request), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + + // Make sure total block size is permissable + if (m_team_size * m_vector_length > 1024) { + Impl::throw_runtime_exception( + std::string("Kokkos::TeamPolicy< Cuda > the team size is too large. " + "Team size x vector length must be smaller than 1024.")); } + } - TeamPolicyInternal( int league_size_ - , const Kokkos::AUTO_t & /* team_size_request */ - , int vector_length_request = 1 ) - : m_space( typename traits::execution_space() ) - , m_league_size( league_size_ ) - , m_team_size( -1 ) - , m_vector_length ( verify_requested_vector_length(vector_length_request) ) - , m_team_scratch_size {0,0} - , m_thread_scratch_size {0,0} - , m_chunk_size ( 32 ) - { - // Make sure league size is permissible - if(league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) - Impl::throw_runtime_exception( "Requested too large league_size for TeamPolicy on Cuda execution space."); - } + TeamPolicyInternal(int league_size_, + const Kokkos::AUTO_t& /* team_size_request */ + , + int vector_length_request = 1) + : m_space(typename traits::execution_space()), + m_league_size(league_size_), + m_team_size(-1), + m_vector_length(verify_requested_vector_length(vector_length_request)), + m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_chunk_size(32) { + // Make sure league size is permissable + if (league_size_ >= int(Impl::cuda_internal_maximum_grid_count())) + Impl::throw_runtime_exception( + "Requested too large league_size for TeamPolicy on Cuda execution " + "space."); + } - inline int chunk_size() const { return m_chunk_size ; } + inline int chunk_size() const { return m_chunk_size; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal set_chunk_size(typename traits::index_type chunk_size_) const { + inline TeamPolicyInternal set_chunk_size( + typename traits::index_type chunk_size_) const { TeamPolicyInternal p = *this; - p.m_chunk_size = chunk_size_; + p.m_chunk_size = chunk_size_; return p; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team) const { - TeamPolicyInternal p = *this; + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team) const { + TeamPolicyInternal p = *this; p.m_team_scratch_size[level] = per_team.value; return p; }; - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; p.m_thread_scratch_size[level] = per_thread.value; return p; }; - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; - p.m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; + p.m_team_scratch_size[level] = per_team.value; p.m_thread_scratch_size[level] = per_thread.value; return p; }; #else /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal& set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal& set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size(const int& level, + const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } #endif - typedef Kokkos::Impl::CudaTeamMember member_type ; + typedef Kokkos::Impl::CudaTeamMember member_type; -protected: + protected: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal internal_set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal internal_set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } #endif + + template + int internal_team_size_common(const FunctorType& f, + BlockSizeCallable&& block_size_callable) const { + using closure_type = ClosureType; + using functor_value_traits = + Impl::FunctorValueTraits; + + cudaFuncAttributes attr = + CudaParallelLaunch:: + get_cuda_func_attributes(); + const int block_size = std::forward(block_size_callable)( + space().impl_internal_space_instance(), attr, f, + (size_t)vector_length(), + (size_t)team_scratch_size(0) + 2 * sizeof(double), + (size_t)thread_scratch_size(0) + sizeof(double) + + ((functor_value_traits::StaticValueSize != 0) + ? 0 + : functor_value_traits::value_size(f))); + KOKKOS_ASSERT(block_size > 0); + + // Currently we require Power-of-2 team size for reductions. + int p2 = 1; + while (p2 <= block_size) p2 *= 2; + p2 /= 2; + return p2 / vector_length(); + } + + template + int internal_team_size_max(const FunctorType& f) const { + return internal_team_size_common( + f, + Kokkos::Impl::cuda_get_max_block_size); + } + + template + int internal_team_size_recommended(const FunctorType& f) const { + return internal_team_size_common( + f, + Kokkos::Impl::cuda_get_opt_block_size); + } }; -} // namspace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -472,262 +564,268 @@ protected: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType - , Kokkos::RangePolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy; -private: +template +class ParallelFor, Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::launch_bounds LaunchBounds ; + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::launch_bounds LaunchBounds; - const FunctorType m_functor ; - const Policy m_policy ; + const FunctorType m_functor; + const Policy m_policy; - ParallelFor() = delete ; - ParallelFor & operator = ( const ParallelFor & ) = delete ; + ParallelFor() = delete; + ParallelFor& operator=(const ParallelFor&) = delete; - template< class TagType > + template inline __device__ - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member i ) const - { m_functor( i ); } + typename std::enable_if::value>::type + exec_range(const Member i) const { + m_functor(i); + } - template< class TagType > + template inline __device__ - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member i ) const - { m_functor( TagType() , i ); } + typename std::enable_if::value>::type + exec_range(const Member i) const { + m_functor(TagType(), i); + } -public: + public: + typedef FunctorType functor_type; - typedef FunctorType functor_type ; + inline __device__ void operator()(void) const { + const Member work_stride = blockDim.y * gridDim.x; + const Member work_end = m_policy.end(); - inline - __device__ - void operator()(void) const - { - const Member work_stride = blockDim.y * gridDim.x ; - const Member work_end = m_policy.end(); - - for ( Member - iwork = m_policy.begin() + threadIdx.y + blockDim.y * blockIdx.x ; - iwork < work_end ; - iwork = iwork < work_end - work_stride ? iwork + work_stride : work_end) { - this-> template exec_range< WorkTag >( iwork ); - } + for (Member iwork = + m_policy.begin() + threadIdx.y + blockDim.y * blockIdx.x; + iwork < work_end; + iwork = iwork < work_end - work_stride ? iwork + work_stride + : work_end) { + this->template exec_range(iwork); } + } - inline - void execute() const - { - const typename Policy::index_type nwork = m_policy.end() - m_policy.begin(); - - cudaFuncAttributes attr = CudaParallelLaunch< ParallelFor, LaunchBounds >:: - get_cuda_func_attributes(); - const int block_size = Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( - m_policy.space().impl_internal_space_instance(), - attr, m_functor , 1, 0 , 0 ); - const dim3 block( 1 , block_size , 1); - const dim3 grid( std::min( typename Policy::index_type(( nwork + block.y - 1 ) / block.y) , - typename Policy::index_type(cuda_internal_maximum_grid_count()) ) , 1 , 1); - - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_policy.space().impl_internal_space_instance() , false ); + inline void execute() const { + const typename Policy::index_type nwork = m_policy.end() - m_policy.begin(); + + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + const int block_size = + Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, m_functor, 1, + 0, 0); + dim3 block(1, block_size, 1); + dim3 grid( + std::min( + typename Policy::index_type((nwork + block.y - 1) / block.y), + typename Policy::index_type(cuda_internal_maximum_grid_count())), + 1, 1); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); } +#endif - ParallelFor( const FunctorType & arg_functor , - const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - { } + CudaParallelLaunch( + *this, grid, block, 0, m_policy.space().impl_internal_space_instance(), + false); + } + ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), m_policy(arg_policy) {} }; - // MDRangePolicy impl -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType - , Kokkos::MDRangePolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::MDRangePolicy< Traits ... > Policy ; -private: +template +class ParallelFor, Kokkos::Cuda> { + public: + typedef Kokkos::MDRangePolicy Policy; + + private: using RP = Policy; typedef typename Policy::array_index_type array_index_type; typedef typename Policy::index_type index_type; typedef typename Policy::launch_bounds LaunchBounds; + const FunctorType m_functor; + const Policy m_rp; - const FunctorType m_functor ; - const Policy m_rp ; - -public: - - inline - __device__ - void operator()(void) const - { - Kokkos::Impl::Refactor::DeviceIterateTile(m_rp,m_functor).exec_range(); - } - + public: + inline __device__ void operator()(void) const { + Kokkos::Impl::Refactor::DeviceIterateTile( + m_rp, m_functor) + .exec_range(); + } - inline - void execute() const - { - if(m_rp.m_num_tiles==0) return; - const array_index_type maxblocks = static_cast(m_rp.space().impl_internal_space_instance()->m_maxBlock); - if ( RP::rank == 2 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , 1); + inline void execute() const { + if (m_rp.m_num_tiles == 0) return; + const array_index_type maxblocks = static_cast( + m_rp.space().impl_internal_space_instance()->m_maxBlock); + if (RP::rank == 2) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], 1); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , 1 - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 3 ) - { - const dim3 block( m_rp.m_tile[0] , m_rp.m_tile[1] , m_rp.m_tile[2] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + 1); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 3) { + const dim3 block(m_rp.m_tile[0], m_rp.m_tile[1], m_rp.m_tile[2]); const dim3 grid( - std::min( ( m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1 ) / block.x , maxblocks ) - , std::min( ( m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 4 ) - { - // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2] , m_rp.m_tile[3] ); + std::min((m_rp.m_upper[0] - m_rp.m_lower[0] + block.x - 1) / block.x, + maxblocks), + std::min((m_rp.m_upper[1] - m_rp.m_lower[1] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.z - 1) / block.z, + maxblocks)); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 4) { + // id0,id1 encoded within threadIdx.x; id2 to threadIdx.y; id3 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], m_rp.m_tile[2], + m_rp.m_tile[3]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1 ) / block.y , maxblocks ) - , std::min( ( m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 5 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[2] - m_rp.m_lower[2] + block.y - 1) / block.y, + maxblocks), + std::min((m_rp.m_upper[3] - m_rp.m_lower[3] + block.z - 1) / block.z, + maxblocks)); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 5) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], m_rp.m_tile[4]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( ( m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1 ) / block.z , maxblocks ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else if ( RP::rank == 6 ) - { - // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to threadIdx.z - const dim3 block( m_rp.m_tile[0]*m_rp.m_tile[1] , m_rp.m_tile[2]*m_rp.m_tile[3] , m_rp.m_tile[4]*m_rp.m_tile[5] ); + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min((m_rp.m_upper[4] - m_rp.m_lower[4] + block.z - 1) / block.z, + maxblocks)); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else if (RP::rank == 6) { + // id0,id1 encoded within threadIdx.x; id2,id3 to threadIdx.y; id4,id5 to + // threadIdx.z + const dim3 block(m_rp.m_tile[0] * m_rp.m_tile[1], + m_rp.m_tile[2] * m_rp.m_tile[3], + m_rp.m_tile[4] * m_rp.m_tile[5]); const dim3 grid( - std::min( static_cast( m_rp.m_tile_end[0] * m_rp.m_tile_end[1] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[2] * m_rp.m_tile_end[3] ) - , static_cast(maxblocks) ) - , std::min( static_cast( m_rp.m_tile_end[4] * m_rp.m_tile_end[5] ) - , static_cast(maxblocks) ) - ); - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this , grid , block , 0 , m_rp.space().impl_internal_space_instance() , false ); - } - else - { + std::min( + static_cast(m_rp.m_tile_end[0] * m_rp.m_tile_end[1]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[2] * m_rp.m_tile_end[3]), + static_cast(maxblocks)), + std::min( + static_cast(m_rp.m_tile_end[4] * m_rp.m_tile_end[5]), + static_cast(maxblocks))); + CudaParallelLaunch( + *this, grid, block, 0, m_rp.space().impl_internal_space_instance(), + false); + } else { printf("Kokkos::MDRange Error: Exceeded rank bounds with Cuda\n"); Kokkos::abort("Aborting"); } - } //end execute + } // end execute -// inline - ParallelFor( const FunctorType & arg_functor - , Policy arg_policy ) - : m_functor( arg_functor ) - , m_rp( arg_policy ) - {} + // inline + ParallelFor(const FunctorType& arg_functor, Policy arg_policy) + : m_functor(arg_functor), m_rp(arg_policy) {} }; +template +class ParallelFor, + Kokkos::Cuda> { + public: + typedef TeamPolicyInternal Policy; -template< class FunctorType , class ... Properties > -class ParallelFor< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , Kokkos::Cuda - > -{ -public: - typedef TeamPolicyInternal< Kokkos::Cuda , Properties ... > Policy ; -private: - - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::launch_bounds LaunchBounds ; - -public: - - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::launch_bounds LaunchBounds; -private: + public: + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; - // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == blockDim.z == 1 - // shared memory utilization: + private: + // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == + // blockDim.z == 1 shared memory utilization: // // [ team reduce space ] // [ team shared space ] // - const FunctorType m_functor ; - const Policy m_policy ; - const size_type m_league_size ; - int m_team_size ; - const size_type m_vector_size ; - int m_shmem_begin ; - int m_shmem_size ; - void* m_scratch_ptr[2] ; - int m_scratch_size[2] ; - - template< class TagType > + const FunctorType m_functor; + const Policy m_policy; + const size_type m_league_size; + int m_team_size; + const size_type m_vector_size; + int m_shmem_begin; + int m_shmem_size; + void* m_scratch_ptr[2]; + int m_scratch_size[2]; + + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_team( const Member & member ) const - { m_functor( member ); } + typename std::enable_if::value>::type + exec_team(const Member& member) const { + m_functor(member); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_team( const Member & member ) const - { m_functor( TagType() , member ); } - -public: + typename std::enable_if::value>::type + exec_team(const Member& member) const { + m_functor(TagType(), member); + } - __device__ inline - void operator()(void) const - { + public: + __device__ inline void operator()(void) const { // Iterate this block through the league int64_t threadid = 0; - if ( m_scratch_size[1]>0 ) { + if (m_scratch_size[1] > 0) { __shared__ int64_t base_thread_id; - if (threadIdx.x==0 && threadIdx.y==0 ) { - threadid = (blockIdx.x*blockDim.z + threadIdx.z) % - (Kokkos::Impl::g_device_cuda_lock_arrays.n / (blockDim.x * blockDim.y)); + if (threadIdx.x == 0 && threadIdx.y == 0) { + threadid = (blockIdx.x * blockDim.z + threadIdx.z) % + (Kokkos::Impl::g_device_cuda_lock_arrays.n / + (blockDim.x * blockDim.y)); threadid *= blockDim.x * blockDim.y; int done = 0; while (!done) { - done = (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid],0,1)); - if(!done) { + done = + (0 == + atomicCAS( + &Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid], + 0, 1)); + if (!done) { threadid += blockDim.x * blockDim.y; - if(int64_t(threadid+blockDim.x * blockDim.y) >= int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) threadid = 0; + if (int64_t(threadid + blockDim.x * blockDim.y) >= + int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) + threadid = 0; } } base_thread_id = threadid; @@ -736,79 +834,102 @@ public: threadid = base_thread_id; } - const int int_league_size = (int)m_league_size; - for ( int league_rank = blockIdx.x ; league_rank < int_league_size ; league_rank += gridDim.x ) { - - this-> template exec_team< WorkTag >( - typename Policy::member_type( kokkos_impl_cuda_shared_memory() - , m_shmem_begin - , m_shmem_size - , (void*) ( ((char*)m_scratch_ptr[1]) + ptrdiff_t(threadid/(blockDim.x*blockDim.y)) * m_scratch_size[1]) - , m_scratch_size[1] - , league_rank - , m_league_size ) ); - } - if ( m_scratch_size[1]>0 ) { + for (int league_rank = blockIdx.x; league_rank < int_league_size; + league_rank += gridDim.x) { + this->template exec_team(typename Policy::member_type( + kokkos_impl_cuda_shared_memory(), m_shmem_begin, m_shmem_size, + (void*)(((char*)m_scratch_ptr[1]) + + ptrdiff_t(threadid / (blockDim.x * blockDim.y)) * + m_scratch_size[1]), + m_scratch_size[1], league_rank, m_league_size)); + } + if (m_scratch_size[1] > 0) { __syncthreads(); - if (threadIdx.x==0 && threadIdx.y==0 ) - Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid]=0; + if (threadIdx.x == 0 && threadIdx.y == 0) + Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid] = 0; } } - inline - void execute() const - { - const int64_t shmem_size_total = m_shmem_begin + m_shmem_size ; - const dim3 grid( int(m_league_size) , 1 , 1 ); - const dim3 block( int(m_vector_size) , int(m_team_size) , 1 ); - - CudaParallelLaunch< ParallelFor, LaunchBounds >( *this, grid, block, shmem_size_total, m_policy.space().impl_internal_space_instance() , true ); // copy to device and execute + inline void execute() const { + const int64_t shmem_size_total = m_shmem_begin + m_shmem_size; + dim3 grid(int(m_league_size), 1, 1); + const dim3 block(int(m_vector_size), int(m_team_size), 1); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + grid = dim3(1, 1, 1); } +#endif - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy - ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_league_size( arg_policy.league_size() ) - , m_team_size( arg_policy.team_size() ) - , m_vector_size( arg_policy.vector_length() ) - { - cudaFuncAttributes attr = CudaParallelLaunch< ParallelFor, LaunchBounds >:: - get_cuda_func_attributes(); - m_team_size = m_team_size>=0?m_team_size:Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( + CudaParallelLaunch( + *this, grid, block, shmem_size_total, m_policy.space().impl_internal_space_instance(), - attr, m_functor , m_vector_size, - m_policy.team_scratch_size(0), m_policy.thread_scratch_size(0) )/m_vector_size; - - m_shmem_begin = ( sizeof(double) * ( m_team_size + 2 ) ); - m_shmem_size = ( m_policy.scratch_size(0,m_team_size) + FunctorTeamShmemSize< FunctorType >::value( m_functor , m_team_size ) ); - m_scratch_size[0] = m_policy.scratch_size(0,m_team_size); - m_scratch_size[1] = m_policy.scratch_size(1,m_team_size); - - // Functor's reduce memory, team scan memory, and team shared memory depend upon team size. - m_scratch_ptr[0] = NULL; - m_scratch_ptr[1] = m_team_size<=0?NULL:cuda_resize_scratch_space(static_cast(m_scratch_size[1])*static_cast(Cuda::concurrency()/(m_team_size*m_vector_size))); - - const int shmem_size_total = m_shmem_begin + m_shmem_size ; - if ( m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size_total ) { - printf("%i %i\n",m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock,shmem_size_total); - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelFor< Cuda > insufficient shared memory")); - } + true); // copy to device and execute + } - if ( int(m_team_size) > - int(Kokkos::Impl::cuda_get_max_block_size< FunctorType, LaunchBounds > - ( m_policy.space().impl_internal_space_instance(), - attr, arg_functor , arg_policy.vector_length(), arg_policy.team_scratch_size(0),arg_policy.thread_scratch_size(0) ) / arg_policy.vector_length())) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelFor< Cuda > requested too large team size.")); - } + ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), + m_policy(arg_policy), + m_league_size(arg_policy.league_size()), + m_team_size(arg_policy.team_size()), + m_vector_size(arg_policy.vector_length()) { + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + m_team_size = + m_team_size >= 0 + ? m_team_size + : Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, + m_functor, m_vector_size, m_policy.team_scratch_size(0), + m_policy.thread_scratch_size(0)) / + m_vector_size; + + m_shmem_begin = (sizeof(double) * (m_team_size + 2)); + m_shmem_size = + (m_policy.scratch_size(0, m_team_size) + + FunctorTeamShmemSize::value(m_functor, m_team_size)); + m_scratch_size[0] = m_policy.scratch_size(0, m_team_size); + m_scratch_size[1] = m_policy.scratch_size(1, m_team_size); + + // Functor's reduce memory, team scan memory, and team shared memory depend + // upon team size. + m_scratch_ptr[0] = NULL; + m_scratch_ptr[1] = + m_team_size <= 0 + ? NULL + : cuda_resize_scratch_space( + static_cast(m_scratch_size[1]) * + static_cast(Cuda::concurrency() / + (m_team_size * m_vector_size))); + + const int shmem_size_total = m_shmem_begin + m_shmem_size; + if (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size_total) { + printf( + "%i %i\n", + m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock, + shmem_size_total); + Kokkos::Impl::throw_runtime_exception(std::string( + "Kokkos::Impl::ParallelFor< Cuda > insufficient shared memory")); + } + + if (int(m_team_size) > + int(Kokkos::Impl::cuda_get_max_block_size( + m_policy.space().impl_internal_space_instance(), attr, + arg_functor, arg_policy.vector_length(), + arg_policy.team_scratch_size(0), + arg_policy.thread_scratch_size(0)) / + arg_policy.vector_length())) { + Kokkos::Impl::throw_runtime_exception(std::string( + "Kokkos::Impl::ParallelFor< Cuda > requested too large team size.")); } + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -816,576 +937,696 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ReducerType, class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReducerType - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy ; -private: +template +class ParallelReduce, ReducerType, + Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; + private: + typedef typename Policy::WorkRange WorkRange; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::member_type Member; + typedef typename Policy::launch_bounds LaunchBounds; - typedef typename Policy::WorkRange WorkRange ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::member_type Member ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; - - typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTagFwd > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTagFwd > ValueInit ; - typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTagFwd > ValueJoin ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::value_type value_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Kokkos::Cuda::size_type size_type ; - typedef typename Policy::index_type index_type ; - - // Algorithmic constraints: blockSize is a power of two AND blockDim.y == blockDim.z == 1 - - const FunctorType m_functor ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - const bool m_result_ptr_device_accessible ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type * m_unified_space ; - - // Shall we use the shfl based reduction or not (only use it for static sized types of more than 128bit) - enum { UseShflReduction = false };//((sizeof(value_type)>2*sizeof(double)) && ValueTraits::StaticValueSize) }; - // Some crutch to do function overloading -private: + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef Kokkos::Impl::FunctorValueTraits + ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueJoin ValueJoin; + + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Kokkos::Cuda::size_type size_type; + typedef typename Policy::index_type index_type; + + // Algorithmic constraints: blockSize is a power of two AND blockDim.y == + // blockDim.z == 1 + + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const bool m_result_ptr_device_accessible; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type* m_unified_space; + + // Shall we use the shfl based reduction or not (only use it for static sized + // types of more than 128bit) + enum { + UseShflReduction = false + }; //((sizeof(value_type)>2*sizeof(double)) && ValueTraits::StaticValueSize) + //}; + // Some crutch to do function overloading + private: typedef double DummyShflReductionType; typedef int DummySHMEMReductionType; -public: + public: // Make the exec_range calls call to Reduce::DeviceIterateTile - template< class TagType > - __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update ) const - { m_functor( i , update ); } - - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update ) const - { m_functor( TagType() , i , update ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update) const { + m_functor(i, update); + } + template __device__ inline - void operator() () const { -/* run(Kokkos::Impl::if_c::select(1,1.0) ); + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update) const { + m_functor(TagType(), i, update); } - __device__ inline - void run(const DummySHMEMReductionType& ) const - {*/ - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) / sizeof(size_type) ); + __device__ inline void operator()() const { + /* run(Kokkos::Impl::if_c::select(1,1.0) ); + } + + __device__ inline + void run(const DummySHMEMReductionType& ) const + {*/ + const integral_nonzero_constant + word_count(ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)) / + sizeof(size_type)); { reference_type value = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + kokkos_impl_cuda_shared_memory() + + threadIdx.y * word_count.value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of + // work to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically + // equivalent. - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , value ); + for (Member iwork = range.begin() + threadIdx.y, iwork_end = range.end(); + iwork < iwork_end; iwork += blockDim.y) { + this->template exec_range(iwork, value); } } // Reduce with final value at blockDim.y - 1 location. - if ( cuda_single_inter_block_reduce_scan( - ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ) ) { - - // This is the final block with the final result at the final threads' location - - size_type * const shared = kokkos_impl_cuda_shared_memory() + ( blockDim.y - 1 ) * word_count.value ; - size_type * const global = m_result_ptr_device_accessible? reinterpret_cast(m_result_ptr) : - ( m_unified_space ? m_unified_space : m_scratch_space ); - - if ( threadIdx.y == 0 ) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , shared ); + if (cuda_single_inter_block_reduce_scan( + ReducerConditional::select(m_functor, m_reducer), blockIdx.x, + gridDim.x, kokkos_impl_cuda_shared_memory(), + m_scratch_space, m_scratch_flags)) { + // This is the final block with the final result at the final threads' + // location + + size_type* const shared = kokkos_impl_cuda_shared_memory() + + (blockDim.y - 1) * word_count.value; + size_type* const global = + m_result_ptr_device_accessible + ? reinterpret_cast(m_result_ptr) + : (m_unified_space ? m_unified_space : m_scratch_space); + + if (threadIdx.y == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), shared); } - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } - for ( unsigned i = threadIdx.y ; i < word_count.value ; i += blockDim.y ) { global[i] = shared[i]; } + for (unsigned i = threadIdx.y; i < word_count.value; i += blockDim.y) { + global[i] = shared[i]; + } } } -/* __device__ inline - void run(const DummyShflReductionType&) const - { - value_type value; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. - - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); - - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , value ); - } - - pointer_type const result = (pointer_type) (m_unified_space ? m_unified_space : m_scratch_space) ; - - int max_active_thread = range.end()-range.begin() < blockDim.y ? range.end() - range.begin():blockDim.y; - - max_active_thread = (max_active_thread == 0)?blockDim.y:max_active_thread; + /* __device__ inline + void run(const DummyShflReductionType&) const + { + value_type value; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &value); + // Number of blocks is bounded so that the reduction can be limited to + two passes. + // Each thread block is given an approximately equal amount of work to + perform. + // Accumulate the values for this block. + // The accumulation ordering does not match the final pass, but is + arithmatically equivalent. + + const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + + for ( Member iwork = range.begin() + threadIdx.y , iwork_end = + range.end() ; iwork < iwork_end ; iwork += blockDim.y ) { this-> template + exec_range< WorkTag >( iwork , value ); + } - value_type init; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &init); - if(Impl::cuda_inter_block_reduction - (value,init,ValueJoin(ReducerConditional::select(m_functor , m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { - const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; - if(id==0) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); - *result = value; + pointer_type const result = (pointer_type) (m_unified_space ? + m_unified_space : m_scratch_space) ; + + int max_active_thread = range.end()-range.begin() < blockDim.y ? + range.end() - range.begin():blockDim.y; + + max_active_thread = (max_active_thread == + 0)?blockDim.y:max_active_thread; + + value_type init; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &init); + if(Impl::cuda_inter_block_reduction + (value,init,ValueJoin(ReducerConditional::select(m_functor , + m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { + const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; + if(id==0) { + Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( + ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); + *result = value; + } } - } - }*/ + }*/ // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - unsigned n = CudaTraits::WarpSize * 8 ; - int shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - while ( (n && (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size)) || - (n > static_cast(Kokkos::Impl::cuda_get_max_block_size< ParallelReduce, LaunchBounds>( f , 1, shmem_size , 0 )))) { - n >>= 1 ; - shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - } - return n ; - } - - inline - void execute() - { - const index_type nwork = m_policy.end() - m_policy.begin(); - if ( nwork ) { - const int block_size = local_block_size( m_functor ); - - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_size /* block_size == max block_count */ ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) ); - m_unified_space = cuda_internal_scratch_unified( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) ); - - // REQUIRED ( 1 , N , 1 ) - const dim3 block( 1 , block_size , 1 ); - // Required grid.x <= block.y - const dim3 grid( std::min( int(block.y) , int( ( nwork + block.y - 1 ) / block.y ) ) , 1 , 1 ); + inline unsigned local_block_size(const FunctorType& f) { + unsigned n = CudaTraits::WarpSize * 8; + int shmem_size = + cuda_single_inter_block_reduce_scan_shmem( + f, n); + while ( + (n && + (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size)) || + (n > static_cast( + Kokkos::Impl::cuda_get_max_block_size< + ParallelReduce, LaunchBounds>(f, 1, shmem_size, 0)))) { + n >>= 1; + shmem_size = cuda_single_inter_block_reduce_scan_shmem(f, n); + } + return n; + } - const int shmem = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( m_functor , block.y ); + inline void execute() { + const index_type nwork = m_policy.end() - m_policy.begin(); + if (nwork) { + const int block_size = local_block_size(m_functor); + + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer)) * + block_size /* block_size == max block_count */); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type)); + m_unified_space = cuda_internal_scratch_unified( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer))); + + // REQUIRED ( 1 , N , 1 ) + dim3 block(1, block_size, 1); + // Required grid.x <= block.y + dim3 grid(std::min(int(block.y), int((nwork + block.y - 1) / block.y)), 1, + 1); + + const int shmem = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(m_functor, + block.y); + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } +#endif - CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute - if(!m_result_ptr_device_accessible) { + if (!m_result_ptr_device_accessible) { Cuda().fence(); - if ( m_result_ptr ) { - if ( m_unified_space ) { - const int count = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); - for ( int i = 0 ; i < count ; ++i ) { m_result_ptr[i] = pointer_type(m_unified_space)[i] ; } - } - else { - const int size = ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ); - DeepCopy( m_result_ptr , m_scratch_space , size ); + if (m_result_ptr) { + if (m_unified_space) { + const int count = ValueTraits::value_count( + ReducerConditional::select(m_functor, m_reducer)); + for (int i = 0; i < count; ++i) { + m_result_ptr[i] = pointer_type(m_unified_space)[i]; + } + } else { + const int size = ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)); + DeepCopy(m_result_ptr, m_scratch_space, size); } } } - } - else { + } else { if (m_result_ptr) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); } } } - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result - , typename std::enable_if< - Kokkos::is_view< ViewType >::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ViewType::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - { } - - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ReducerType & reducer) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ReducerType::result_view_type::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - { } + template + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} + + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} }; - // MDRangePolicy impl -template< class FunctorType , class ReducerType, class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::MDRangePolicy< Traits ... > - , ReducerType - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::MDRangePolicy< Traits ... > Policy ; -private: - - typedef typename Policy::array_index_type array_index_type; - typedef typename Policy::index_type index_type; - - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::member_type Member ; - typedef typename Policy::launch_bounds LaunchBounds; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; - typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; +template +class ParallelReduce, ReducerType, + Kokkos::Cuda> { + public: + typedef Kokkos::MDRangePolicy Policy; - typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTagFwd > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTagFwd > ValueInit ; - typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTagFwd > ValueJoin ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::value_type value_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; - - // Algorithmic constraints: blockSize is a power of two AND blockDim.y == blockDim.z == 1 - - const FunctorType m_functor ; - const Policy m_policy ; // used for workrange and nwork - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - const bool m_result_ptr_device_accessible ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type * m_unified_space ; + private: + typedef typename Policy::array_index_type array_index_type; + typedef typename Policy::index_type index_type; - typedef typename Kokkos::Impl::Reduce::DeviceIterateTile DeviceIteratePattern; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::member_type Member; + typedef typename Policy::launch_bounds LaunchBounds; - // Shall we use the shfl based reduction or not (only use it for static sized types of more than 128bit - enum { UseShflReduction = ((sizeof(value_type)>2*sizeof(double)) && (ValueTraits::StaticValueSize!=0)) }; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; + typedef typename ReducerConditional::type ReducerTypeFwd; + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef Kokkos::Impl::FunctorValueTraits + ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueJoin ValueJoin; + + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::value_type value_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; + + // Algorithmic constraints: blockSize is a power of two AND blockDim.y == + // blockDim.z == 1 + + const FunctorType m_functor; + const Policy m_policy; // used for workrange and nwork + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const bool m_result_ptr_device_accessible; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type* m_unified_space; + + typedef typename Kokkos::Impl::Reduce::DeviceIterateTile< + Policy::rank, Policy, FunctorType, typename Policy::work_tag, + reference_type> + DeviceIteratePattern; + + // Shall we use the shfl based reduction or not (only use it for static sized + // types of more than 128bit + enum { + UseShflReduction = ((sizeof(value_type) > 2 * sizeof(double)) && + (ValueTraits::StaticValueSize != 0)) + }; // Some crutch to do function overloading -private: + private: typedef double DummyShflReductionType; typedef int DummySHMEMReductionType; -public: - inline - __device__ - void - exec_range( reference_type update ) const - { - Kokkos::Impl::Reduce::DeviceIterateTile(m_policy, m_functor, update).exec_range(); + public: + inline __device__ void exec_range(reference_type update) const { + Kokkos::Impl::Reduce::DeviceIterateTile(m_policy, m_functor, + update) + .exec_range(); } - inline - __device__ - void operator() (void) const { -/* run(Kokkos::Impl::if_c::select(1,1.0) ); - } + inline __device__ void operator()(void) const { + /* run(Kokkos::Impl::if_c::select(1,1.0) ); + } - __device__ inline - void run(const DummySHMEMReductionType& ) const - {*/ - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) / sizeof(size_type) ); + __device__ inline + void run(const DummySHMEMReductionType& ) const + {*/ + const integral_nonzero_constant + word_count(ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)) / + sizeof(size_type)); { reference_type value = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + kokkos_impl_cuda_shared_memory() + + threadIdx.y * word_count.value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of + // work to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically + // equivalent. - this-> exec_range( value ); + this->exec_range(value); } // Reduce with final value at blockDim.y - 1 location. // Problem: non power-of-two blockDim - if ( cuda_single_inter_block_reduce_scan( - ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ) ) { - - // This is the final block with the final result at the final threads' location - size_type * const shared = kokkos_impl_cuda_shared_memory() + ( blockDim.y - 1 ) * word_count.value ; - size_type * const global = m_result_ptr_device_accessible? reinterpret_cast(m_result_ptr) : - ( m_unified_space ? m_unified_space : m_scratch_space ); - - if ( threadIdx.y == 0 ) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , shared ); + if (cuda_single_inter_block_reduce_scan( + ReducerConditional::select(m_functor, m_reducer), blockIdx.x, + gridDim.x, kokkos_impl_cuda_shared_memory(), + m_scratch_space, m_scratch_flags)) { + // This is the final block with the final result at the final threads' + // location + size_type* const shared = kokkos_impl_cuda_shared_memory() + + (blockDim.y - 1) * word_count.value; + size_type* const global = + m_result_ptr_device_accessible + ? reinterpret_cast(m_result_ptr) + : (m_unified_space ? m_unified_space : m_scratch_space); + + if (threadIdx.y == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), shared); } - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } - for ( unsigned i = threadIdx.y ; i < word_count.value ; i += blockDim.y ) { global[i] = shared[i]; } + for (unsigned i = threadIdx.y; i < word_count.value; i += blockDim.y) { + global[i] = shared[i]; + } } } -/* __device__ inline - void run(const DummyShflReductionType&) const - { - - value_type value; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. - - const Member work_part = - ( ( m_policy.m_num_tiles + ( gridDim.x - 1 ) ) / gridDim.x ); //portion of tiles handled by each block - - this-> exec_range( value ); - - pointer_type const result = (pointer_type) (m_unified_space ? m_unified_space : m_scratch_space) ; - - int max_active_thread = work_part < blockDim.y ? work_part:blockDim.y; - max_active_thread = (max_active_thread == 0)?blockDim.y:max_active_thread; - - value_type init; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &init); - if(Impl::cuda_inter_block_reduction - (value,init,ValueJoin(ReducerConditional::select(m_functor , m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { - const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; - if(id==0) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); - *result = value; + /* __device__ inline + void run(const DummyShflReductionType&) const + { + + value_type value; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &value); + // Number of blocks is bounded so that the reduction can be limited to + two passes. + // Each thread block is given an approximately equal amount of work to + perform. + // Accumulate the values for this block. + // The accumulation ordering does not match the final pass, but is + arithmatically equivalent. + + const Member work_part = + ( ( m_policy.m_num_tiles + ( gridDim.x - 1 ) ) / gridDim.x ); //portion + of tiles handled by each block + + this-> exec_range( value ); + + pointer_type const result = (pointer_type) (m_unified_space ? + m_unified_space : m_scratch_space) ; + + int max_active_thread = work_part < blockDim.y ? work_part:blockDim.y; + max_active_thread = (max_active_thread == + 0)?blockDim.y:max_active_thread; + + value_type init; + ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , + &init); + if(Impl::cuda_inter_block_reduction + (value,init,ValueJoin(ReducerConditional::select(m_functor , + m_reducer)),m_scratch_space,result,m_scratch_flags,max_active_thread)) { + const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; + if(id==0) { + Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( + ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); + *result = value; + } } } - } -*/ + */ // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - unsigned n = CudaTraits::WarpSize * 8 ; - int shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - while ( (n && (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size)) || - (n > static_cast(Kokkos::Impl::cuda_get_max_block_size< ParallelReduce, LaunchBounds>( f , 1, shmem_size , 0 )))) { - n >>= 1 ; - shmem_size = cuda_single_inter_block_reduce_scan_shmem( f , n ); - } - return n ; - } - - inline - void execute() - { - const int nwork = m_policy.m_num_tiles; - if ( nwork ) { - int block_size = m_policy.m_prod_tile_dims; - // CONSTRAINT: Algorithm requires block_size >= product of tile dimensions - // Nearest power of two - int exponent_pow_two = std::ceil( std::log2(block_size) ); - block_size = std::pow(2, exponent_pow_two); - int suggested_blocksize = local_block_size( m_functor ); - - block_size = (block_size > suggested_blocksize) ? block_size : suggested_blocksize ; //Note: block_size must be less than or equal to 512 - - - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_size /* block_size == max block_count */ ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) ); - m_unified_space = cuda_internal_scratch_unified( m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) ); - - // REQUIRED ( 1 , N , 1 ) - const dim3 block( 1 , block_size , 1 ); - // Required grid.x <= block.y - const dim3 grid( std::min( int(block.y) , int( nwork ) ) , 1 , 1 ); - - const int shmem = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( m_functor , block.y ); + inline unsigned local_block_size(const FunctorType& f) { + unsigned n = CudaTraits::WarpSize * 8; + int shmem_size = + cuda_single_inter_block_reduce_scan_shmem( + f, n); + while ( + (n && + (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size)) || + (n > static_cast( + Kokkos::Impl::cuda_get_max_block_size< + ParallelReduce, LaunchBounds>(f, 1, shmem_size, 0)))) { + n >>= 1; + shmem_size = cuda_single_inter_block_reduce_scan_shmem(f, n); + } + return n; + } - CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + inline void execute() { + const int nwork = m_policy.m_num_tiles; + if (nwork) { + int block_size = m_policy.m_prod_tile_dims; + // CONSTRAINT: Algorithm requires block_size >= product of tile dimensions + // Nearest power of two + int exponent_pow_two = std::ceil(std::log2(block_size)); + block_size = std::pow(2, exponent_pow_two); + int suggested_blocksize = local_block_size(m_functor); + + block_size = (block_size > suggested_blocksize) + ? block_size + : suggested_blocksize; // Note: block_size must be less + // than or equal to 512 + + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer)) * + block_size /* block_size == max block_count */); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type)); + m_unified_space = cuda_internal_scratch_unified( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer))); + + // REQUIRED ( 1 , N , 1 ) + const dim3 block(1, block_size, 1); + // Required grid.x <= block.y + const dim3 grid(std::min(int(block.y), int(nwork)), 1, 1); + + const int shmem = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(m_functor, + block.y); + + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute - if(!m_result_ptr_device_accessible) { + if (!m_result_ptr_device_accessible) { Cuda().fence(); - if ( m_result_ptr ) { - if ( m_unified_space ) { - const int count = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); - for ( int i = 0 ; i < count ; ++i ) { m_result_ptr[i] = pointer_type(m_unified_space)[i] ; } - } - else { - const int size = ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ); - DeepCopy( m_result_ptr , m_scratch_space , size ); + if (m_result_ptr) { + if (m_unified_space) { + const int count = ValueTraits::value_count( + ReducerConditional::select(m_functor, m_reducer)); + for (int i = 0; i < count; ++i) { + m_result_ptr[i] = pointer_type(m_unified_space)[i]; + } + } else { + const int size = ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)); + DeepCopy(m_result_ptr, m_scratch_space, size); } } } - } - else { + } else { if (m_result_ptr) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); } } } - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result - , typename std::enable_if< - Kokkos::is_view< ViewType >::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ViewType::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - {} - - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ReducerType & reducer) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ReducerType::result_view_type::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - {} + template + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} + + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0) {} }; - //---------------------------------------------------------------------------- -template< class FunctorType , class ReducerType, class ... Properties > -class ParallelReduce< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , ReducerType - , Kokkos::Cuda - > -{ -public: - typedef TeamPolicyInternal< Kokkos::Cuda, Properties ... > Policy ; -private: - - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; - typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; +template +class ParallelReduce, + ReducerType, Kokkos::Cuda> { + public: + typedef TeamPolicyInternal Policy; + + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::launch_bounds LaunchBounds; - typedef Kokkos::Impl::FunctorValueTraits< ReducerTypeFwd, WorkTagFwd > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd, WorkTagFwd > ValueInit ; - typedef Kokkos::Impl::FunctorValueJoin< ReducerTypeFwd, WorkTagFwd > ValueJoin ; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; + typedef typename ReducerConditional::type ReducerTypeFwd; + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef typename ValueTraits::value_type value_type ; + typedef Kokkos::Impl::FunctorValueTraits + ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueJoin ValueJoin; -public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::reference_type reference_type; + typedef typename ValueTraits::value_type value_type; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; + public: + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; - enum { UseShflReduction = (true && (ValueTraits::StaticValueSize!=0)) }; + enum { UseShflReduction = (true && (ValueTraits::StaticValueSize != 0)) }; -private: + private: typedef double DummyShflReductionType; typedef int DummySHMEMReductionType; - // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == blockDim.z == 1 - // shared memory utilization: + // Algorithmic constraints: blockDim.y is a power of two AND blockDim.y == + // blockDim.z == 1 shared memory utilization: // // [ global reduce space ] // [ team reduce space ] // [ team shared space ] // - const FunctorType m_functor ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - const bool m_result_ptr_device_accessible ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type * m_unified_space ; - size_type m_team_begin ; - size_type m_shmem_begin ; - size_type m_shmem_size ; - void* m_scratch_ptr[2] ; - int m_scratch_size[2] ; - const size_type m_league_size ; - int m_team_size ; - const size_type m_vector_size ; - - template< class TagType > + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + const bool m_result_ptr_device_accessible; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type* m_unified_space; + size_type m_team_begin; + size_type m_shmem_begin; + size_type m_shmem_size; + void* m_scratch_ptr[2]; + int m_scratch_size[2]; + const size_type m_league_size; + int m_team_size; + const size_type m_vector_size; + + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_team( const Member & member , reference_type update ) const - { m_functor( member , update ); } + typename std::enable_if::value>::type + exec_team(const Member& member, reference_type update) const { + m_functor(member, update); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_team( const Member & member , reference_type update ) const - { m_functor( TagType() , member , update ); } - -public: + typename std::enable_if::value>::type + exec_team(const Member& member, reference_type update) const { + m_functor(TagType(), member, update); + } - __device__ inline - void operator() () const { + public: + __device__ inline void operator()() const { int64_t threadid = 0; - if ( m_scratch_size[1]>0 ) { + if (m_scratch_size[1] > 0) { __shared__ int64_t base_thread_id; - if (threadIdx.x==0 && threadIdx.y==0 ) { - threadid = (blockIdx.x*blockDim.z + threadIdx.z) % - (Kokkos::Impl::g_device_cuda_lock_arrays.n / (blockDim.x * blockDim.y)); + if (threadIdx.x == 0 && threadIdx.y == 0) { + threadid = (blockIdx.x * blockDim.z + threadIdx.z) % + (Kokkos::Impl::g_device_cuda_lock_arrays.n / + (blockDim.x * blockDim.y)); threadid *= blockDim.x * blockDim.y; int done = 0; while (!done) { - done = (0 == atomicCAS(&Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid],0,1)); - if(!done) { + done = + (0 == + atomicCAS( + &Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid], + 0, 1)); + if (!done) { threadid += blockDim.x * blockDim.y; - if(int64_t(threadid + blockDim.x * blockDim.y) >= int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) threadid = 0; + if (int64_t(threadid + blockDim.x * blockDim.y) >= + int64_t(Kokkos::Impl::g_device_cuda_lock_arrays.n)) + threadid = 0; } } base_thread_id = threadid; @@ -1394,272 +1635,374 @@ public: threadid = base_thread_id; } - run(Kokkos::Impl::if_c::select(1,1.0), threadid ); - if ( m_scratch_size[1]>0 ) { + run(Kokkos::Impl::if_c::select(1, 1.0), + threadid); + if (m_scratch_size[1] > 0) { __syncthreads(); - if (threadIdx.x==0 && threadIdx.y==0 ) - Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid]=0; + if (threadIdx.x == 0 && threadIdx.y == 0) + Kokkos::Impl::g_device_cuda_lock_arrays.scratch[threadid] = 0; } } - __device__ inline - void run(const DummySHMEMReductionType&, const int& threadid) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) / sizeof(size_type) ); + __device__ inline void run(const DummySHMEMReductionType&, + const int& threadid) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)) / + sizeof(size_type)); reference_type value = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , kokkos_impl_cuda_shared_memory() + threadIdx.y * word_count.value ); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + kokkos_impl_cuda_shared_memory() + + threadIdx.y * word_count.value); // Iterate this block through the league const int int_league_size = (int)m_league_size; - for ( int league_rank = blockIdx.x ; league_rank < int_league_size ; league_rank += gridDim.x ) { - this-> template exec_team< WorkTag > - ( Member( kokkos_impl_cuda_shared_memory() + m_team_begin - , m_shmem_begin - , m_shmem_size - , (void*) ( ((char*)m_scratch_ptr[1]) + ptrdiff_t(threadid/(blockDim.x*blockDim.y)) * m_scratch_size[1]) - , m_scratch_size[1] - , league_rank - , m_league_size ) - , value ); + for (int league_rank = blockIdx.x; league_rank < int_league_size; + league_rank += gridDim.x) { + this->template exec_team( + Member(kokkos_impl_cuda_shared_memory() + m_team_begin, + m_shmem_begin, m_shmem_size, + (void*)(((char*)m_scratch_ptr[1]) + + ptrdiff_t(threadid / (blockDim.x * blockDim.y)) * + m_scratch_size[1]), + m_scratch_size[1], league_rank, m_league_size), + value); } // Reduce with final value at blockDim.y - 1 location. - if ( cuda_single_inter_block_reduce_scan( - ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ) ) { - - // This is the final block with the final result at the final threads' location - - size_type * const shared = kokkos_impl_cuda_shared_memory() + ( blockDim.y - 1 ) * word_count.value ; - size_type * const global = m_result_ptr_device_accessible? reinterpret_cast(m_result_ptr) : - ( m_unified_space ? m_unified_space : m_scratch_space ); - - if ( threadIdx.y == 0 ) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , shared ); + if (cuda_single_inter_block_reduce_scan( + ReducerConditional::select(m_functor, m_reducer), blockIdx.x, + gridDim.x, kokkos_impl_cuda_shared_memory(), + m_scratch_space, m_scratch_flags)) { + // This is the final block with the final result at the final threads' + // location + + size_type* const shared = kokkos_impl_cuda_shared_memory() + + (blockDim.y - 1) * word_count.value; + size_type* const global = + m_result_ptr_device_accessible + ? reinterpret_cast(m_result_ptr) + : (m_unified_space ? m_unified_space : m_scratch_space); + + if (threadIdx.y == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), shared); } - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } - for ( unsigned i = threadIdx.y ; i < word_count.value ; i += blockDim.y ) { global[i] = shared[i]; } + for (unsigned i = threadIdx.y; i < word_count.value; i += blockDim.y) { + global[i] = shared[i]; + } } - } - __device__ inline - void run(const DummyShflReductionType&, const int& threadid) const - { + __device__ inline void run(const DummyShflReductionType&, + const int& threadid) const { value_type value; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &value); + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), &value); // Iterate this block through the league const int int_league_size = (int)m_league_size; - for ( int league_rank = blockIdx.x ; league_rank < int_league_size ; league_rank += gridDim.x ) { - this-> template exec_team< WorkTag > - ( Member( kokkos_impl_cuda_shared_memory() + m_team_begin - , m_shmem_begin - , m_shmem_size - , (void*) ( ((char*)m_scratch_ptr[1]) + ptrdiff_t(threadid/(blockDim.x*blockDim.y)) * m_scratch_size[1]) - , m_scratch_size[1] - , league_rank - , m_league_size ) - , value ); - } - - pointer_type const result = m_result_ptr_device_accessible? m_result_ptr : - (pointer_type) ( m_unified_space ? m_unified_space : m_scratch_space ); + for (int league_rank = blockIdx.x; league_rank < int_league_size; + league_rank += gridDim.x) { + this->template exec_team( + Member(kokkos_impl_cuda_shared_memory() + m_team_begin, + m_shmem_begin, m_shmem_size, + (void*)(((char*)m_scratch_ptr[1]) + + ptrdiff_t(threadid / (blockDim.x * blockDim.y)) * + m_scratch_size[1]), + m_scratch_size[1], league_rank, m_league_size), + value); + } + + pointer_type const result = + m_result_ptr_device_accessible + ? m_result_ptr + : (pointer_type)(m_unified_space ? m_unified_space + : m_scratch_space); value_type init; - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , &init); - if( - Impl::cuda_inter_block_reduction - (value,init,ValueJoin(ReducerConditional::select(m_functor , m_reducer)),m_scratch_space,result,m_scratch_flags,blockDim.y) - //This breaks a test - // Kokkos::Impl::CudaReductionsFunctor::scalar_inter_block_reduction(ReducerConditional::select(m_functor , m_reducer) , blockIdx.x , gridDim.x , - // kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags) + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), &init); + if (Impl::cuda_inter_block_reduction( + value, init, + ValueJoin(ReducerConditional::select(m_functor, m_reducer)), + m_scratch_space, result, m_scratch_flags, blockDim.y) + // This breaks a test + // Kokkos::Impl::CudaReductionsFunctor::scalar_inter_block_reduction(ReducerConditional::select(m_functor + // , m_reducer) , blockIdx.x , gridDim.x , + // kokkos_impl_cuda_shared_memory() , + // m_scratch_space , m_scratch_flags) ) { - const unsigned id = threadIdx.y*blockDim.x + threadIdx.x; - if(id==0) { - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >::final( ReducerConditional::select(m_functor , m_reducer) , (void*) &value ); + const unsigned id = threadIdx.y * blockDim.x + threadIdx.x; + if (id == 0) { + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), (void*)&value); *result = value; } } } - inline - void execute() - { - const int nwork = m_league_size * m_team_size ; - if ( nwork ) { - const int block_count = UseShflReduction? std::min( m_league_size , size_type(1024*32) ) - :std::min( int(m_league_size) , m_team_size ); - - m_scratch_space = cuda_internal_scratch_space(m_policy.space(), ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) * block_count ); - m_scratch_flags = cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) ); - m_unified_space = cuda_internal_scratch_unified( m_policy.space(),ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ) ); - - const dim3 block( m_vector_size , m_team_size , 1 ); - const dim3 grid( block_count , 1 , 1 ); - const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ; + inline void execute() { + const int nwork = m_league_size * m_team_size; + if (nwork) { + const int block_count = + UseShflReduction ? std::min(m_league_size, size_type(1024 * 32)) + : std::min(int(m_league_size), m_team_size); + + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer)) * + block_count); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type)); + m_unified_space = cuda_internal_scratch_unified( + m_policy.space(), ValueTraits::value_size(ReducerConditional::select( + m_functor, m_reducer))); + + dim3 block(m_vector_size, m_team_size, 1); + dim3 grid(block_count, 1, 1); + const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size; + +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } +#endif - CudaParallelLaunch< ParallelReduce, LaunchBounds >( *this, grid, block, shmem_size_total , m_policy.space().impl_internal_space_instance() , true ); // copy to device and execute + CudaParallelLaunch( + *this, grid, block, shmem_size_total, + m_policy.space().impl_internal_space_instance(), + true); // copy to device and execute - if(!m_result_ptr_device_accessible) { - Cuda().fence(); + if (!m_result_ptr_device_accessible) { + Cuda().fence(); - if ( m_result_ptr ) { - if ( m_unified_space ) { - const int count = ValueTraits::value_count( ReducerConditional::select(m_functor , m_reducer) ); - for ( int i = 0 ; i < count ; ++i ) { m_result_ptr[i] = pointer_type(m_unified_space)[i] ; } - } - else { - const int size = ValueTraits::value_size( ReducerConditional::select(m_functor , m_reducer) ); - DeepCopy( m_result_ptr, m_scratch_space, size ); + if (m_result_ptr) { + if (m_unified_space) { + const int count = ValueTraits::value_count( + ReducerConditional::select(m_functor, m_reducer)); + for (int i = 0; i < count; ++i) { + m_result_ptr[i] = pointer_type(m_unified_space)[i]; } + } else { + const int size = ValueTraits::value_size( + ReducerConditional::select(m_functor, m_reducer)); + DeepCopy(m_result_ptr, m_scratch_space, size); } } } - else { - if (m_result_ptr) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); - } + } else { + if (m_result_ptr) { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); } } + } - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result - , typename std::enable_if< - Kokkos::is_view< ViewType >::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy ( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ViewType::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - , m_team_begin( 0 ) - , m_shmem_begin( 0 ) - , m_shmem_size( 0 ) - , m_scratch_ptr{NULL,NULL} - , m_league_size( arg_policy.league_size() ) - , m_team_size( arg_policy.team_size() ) - , m_vector_size( arg_policy.vector_length() ) - { - cudaFuncAttributes attr = CudaParallelLaunch< ParallelReduce, LaunchBounds >:: - get_cuda_func_attributes(); - m_team_size = m_team_size>=0?m_team_size: - Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( - m_policy.space().impl_internal_space_instance(), - attr, m_functor , m_vector_size, - m_policy.team_scratch_size(0), m_policy.thread_scratch_size(0) )/m_vector_size; + template + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0), + m_team_begin(0), + m_shmem_begin(0), + m_shmem_size(0), + m_scratch_ptr{NULL, NULL}, + m_league_size(arg_policy.league_size()), + m_team_size(arg_policy.team_size()), + m_vector_size(arg_policy.vector_length()) { + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + m_team_size = + m_team_size >= 0 + ? m_team_size + : Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, + m_functor, m_vector_size, m_policy.team_scratch_size(0), + m_policy.thread_scratch_size(0)) / + m_vector_size; // Return Init value if the number of worksets is zero - if( m_league_size*m_team_size == 0) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , arg_result.data() ); - return ; - } - - m_team_begin = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( arg_functor , m_team_size ); - m_shmem_begin = sizeof(double) * ( m_team_size + 2 ); - m_shmem_size = m_policy.scratch_size(0,m_team_size) + FunctorTeamShmemSize< FunctorType >::value( arg_functor , m_team_size ); + if (m_league_size * m_team_size == 0) { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + arg_result.data()); + return; + } + + m_team_begin = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(arg_functor, + m_team_size); + m_shmem_begin = sizeof(double) * (m_team_size + 2); + m_shmem_size = + m_policy.scratch_size(0, m_team_size) + + FunctorTeamShmemSize::value(arg_functor, m_team_size); m_scratch_size[0] = m_shmem_size; - m_scratch_size[1] = m_policy.scratch_size(1,m_team_size); - m_scratch_ptr[1] = m_team_size<=0?NULL:cuda_resize_scratch_space(static_cast(m_scratch_size[1])*(static_cast(Cuda::concurrency()/(m_team_size*m_vector_size)))); - - // The global parallel_reduce does not support vector_length other than 1 at the moment - if( (arg_policy.vector_length() > 1) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a vector length of greater than 1 is not currently supported for CUDA for dynamic sized reduction types."); - - if( (m_team_size < 32) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller than 32 is not currently supported with CUDA for dynamic sized reduction types."); - - // Functor's reduce memory, team scan memory, and team shared memory depend upon team size. - - const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ; - - if (! Kokkos::Impl::is_integral_power_of_two( m_team_size ) && !UseShflReduction ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); - } - - if ( m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size_total ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too much L0 scratch memory")); - } - - if ( int(m_team_size) > arg_policy.team_size_max(m_functor,ParallelReduceTag()) ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too large team size.")); + m_scratch_size[1] = m_policy.scratch_size(1, m_team_size); + m_scratch_ptr[1] = + m_team_size <= 0 + ? NULL + : cuda_resize_scratch_space( + static_cast(m_scratch_size[1]) * + (static_cast(Cuda::concurrency() / + (m_team_size * m_vector_size)))); + + // The global parallel_reduce does not support vector_length other than 1 at + // the moment + if ((arg_policy.vector_length() > 1) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a vector length of " + "greater than 1 is not currently supported for CUDA for dynamic " + "sized reduction types."); + + if ((m_team_size < 32) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller " + "than 32 is not currently supported with CUDA for dynamic sized " + "reduction types."); + + // Functor's reduce memory, team scan memory, and team shared memory depend + // upon team size. + + const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size; + + if (!Kokkos::Impl::is_integral_power_of_two(m_team_size) && + !UseShflReduction) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); + } + + if (m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size_total) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too much " + "L0 scratch memory")); + } + + if (int(m_team_size) > + arg_policy.team_size_max(m_functor, m_reducer, ParallelReduceTag())) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too " + "large team size.")); } - } - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ReducerType & reducer) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_result_ptr_device_accessible(MemorySpaceAccess< Kokkos::CudaSpace , typename ReducerType::result_view_type::memory_space>::accessible ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_unified_space( 0 ) - , m_team_begin( 0 ) - , m_shmem_begin( 0 ) - , m_shmem_size( 0 ) - , m_scratch_ptr{NULL,NULL} - , m_league_size( arg_policy.league_size() ) - , m_team_size( arg_policy.team_size() ) - , m_vector_size( arg_policy.vector_length() ) - { - cudaFuncAttributes attr = CudaParallelLaunch< ParallelReduce, LaunchBounds >:: - get_cuda_func_attributes(); - m_team_size = m_team_size>=0?m_team_size: - Kokkos::Impl::cuda_get_opt_block_size< FunctorType, LaunchBounds>( - m_policy.space().impl_internal_space_instance(), - attr, m_functor , m_vector_size, - m_policy.team_scratch_size(0), m_policy.thread_scratch_size(0) )/m_vector_size; + ParallelReduce(const FunctorType& arg_functor, const Policy& arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_result_ptr_device_accessible( + MemorySpaceAccess::accessible), + m_scratch_space(0), + m_scratch_flags(0), + m_unified_space(0), + m_team_begin(0), + m_shmem_begin(0), + m_shmem_size(0), + m_scratch_ptr{NULL, NULL}, + m_league_size(arg_policy.league_size()), + m_team_size(arg_policy.team_size()), + m_vector_size(arg_policy.vector_length()) { + cudaFuncAttributes attr = + CudaParallelLaunch::get_cuda_func_attributes(); + m_team_size = + m_team_size >= 0 + ? m_team_size + : Kokkos::Impl::cuda_get_opt_block_size( + m_policy.space().impl_internal_space_instance(), attr, + m_functor, m_vector_size, m_policy.team_scratch_size(0), + m_policy.thread_scratch_size(0)) / + m_vector_size; // Return Init value if the number of worksets is zero - if( arg_policy.league_size() == 0) { - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , m_result_ptr ); - return ; - } - - m_team_begin = UseShflReduction?0:cuda_single_inter_block_reduce_scan_shmem( arg_functor , m_team_size ); - m_shmem_begin = sizeof(double) * ( m_team_size + 2 ); - m_shmem_size = m_policy.scratch_size(0,m_team_size) + FunctorTeamShmemSize< FunctorType >::value( arg_functor , m_team_size ); + if (arg_policy.league_size() == 0) { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + m_result_ptr); + return; + } + + m_team_begin = + UseShflReduction + ? 0 + : cuda_single_inter_block_reduce_scan_shmem(arg_functor, + m_team_size); + m_shmem_begin = sizeof(double) * (m_team_size + 2); + m_shmem_size = + m_policy.scratch_size(0, m_team_size) + + FunctorTeamShmemSize::value(arg_functor, m_team_size); m_scratch_size[0] = m_shmem_size; - m_scratch_size[1] = m_policy.scratch_size(1,m_team_size); - m_scratch_ptr[1] = m_team_size<=0?NULL:cuda_resize_scratch_space(static_cast(m_scratch_size[1])*static_cast(Cuda::concurrency()/(m_team_size*m_vector_size))); - - // The global parallel_reduce does not support vector_length other than 1 at the moment - if( (arg_policy.vector_length() > 1) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a vector length of greater than 1 is not currently supported for CUDA for dynamic sized reduction types."); - - if( (m_team_size < 32) && !UseShflReduction ) - Impl::throw_runtime_exception( "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller than 32 is not currently supported with CUDA for dynamic sized reduction types."); - - // Functor's reduce memory, team scan memory, and team shared memory depend upon team size. - - const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size ; - - if ( (! Kokkos::Impl::is_integral_power_of_two( m_team_size ) && !UseShflReduction ) || - m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < shmem_size_total ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); + m_scratch_size[1] = m_policy.scratch_size(1, m_team_size); + m_scratch_ptr[1] = + m_team_size <= 0 + ? NULL + : cuda_resize_scratch_space( + static_cast(m_scratch_size[1]) * + static_cast(Cuda::concurrency() / + (m_team_size * m_vector_size))); + + // The global parallel_reduce does not support vector_length other than 1 at + // the moment + if ((arg_policy.vector_length() > 1) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a vector length of " + "greater than 1 is not currently supported for CUDA for dynamic " + "sized reduction types."); + + if ((m_team_size < 32) && !UseShflReduction) + Impl::throw_runtime_exception( + "Kokkos::parallel_reduce with a TeamPolicy using a team_size smaller " + "than 32 is not currently supported with CUDA for dynamic sized " + "reduction types."); + + // Functor's reduce memory, team scan memory, and team shared memory depend + // upon team size. + + const int shmem_size_total = m_team_begin + m_shmem_begin + m_shmem_size; + + if ((!Kokkos::Impl::is_integral_power_of_two(m_team_size) && + !UseShflReduction) || + m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock < + shmem_size_total) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > bad team size")); + } + if (int(m_team_size) > + arg_policy.team_size_max(m_functor, m_reducer, ParallelReduceTag())) { + Kokkos::Impl::throw_runtime_exception( + std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too " + "large team size.")); } - if ( int(m_team_size) > arg_policy.team_size_max(m_functor,ParallelReduceTag()) ) { - Kokkos::Impl::throw_runtime_exception(std::string("Kokkos::Impl::ParallelReduce< Cuda > requested too large team size.")); - } - } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -1667,463 +2010,595 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelScan< FunctorType - , Kokkos::RangePolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy ; -private: - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::WorkRange WorkRange ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::FunctorValueTraits< FunctorType, WorkTag > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< FunctorType, WorkTag > ValueInit ; - typedef Kokkos::Impl::FunctorValueOps< FunctorType, WorkTag > ValueOps ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; - -private: +template +class ParallelScan, Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; + + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::WorkRange WorkRange; + typedef typename Policy::launch_bounds LaunchBounds; + + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueOps ValueOps; + + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; + private: // Algorithmic constraints: // (a) blockDim.y is a power of two // (b) blockDim.y == blockDim.z == 1 // (c) gridDim.x <= blockDim.y * blockDim.y // (d) gridDim.y == gridDim.z == 1 - const FunctorType m_functor ; - const Policy m_policy ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type m_final ; + const FunctorType m_functor; + const Policy m_policy; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type m_final; +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + bool m_run_serial; +#endif - template< class TagType > + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(i, update, final_result); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( TagType() , i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(TagType(), i, update, final_result); + } //---------------------------------------- - __device__ inline - void initial(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void initial(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - size_type * const shared_value = kokkos_impl_cuda_shared_memory() + word_count.value * threadIdx.y ; + size_type* const shared_value = + kokkos_impl_cuda_shared_memory() + + word_count.value * threadIdx.y; - ValueInit::init( m_functor , shared_value ); + ValueInit::init(m_functor, shared_value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of work + // to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically equivalent. - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_value ) , false ); + for (Member iwork = range.begin() + threadIdx.y, iwork_end = range.end(); + iwork < iwork_end; iwork += blockDim.y) { + this->template exec_range( + iwork, ValueOps::reference(shared_value), false); } - // Reduce and scan, writing out scan of blocks' totals and block-groups' totals. - // Blocks' scan values are written to 'blockIdx.x' location. - // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < gridDim.x - cuda_single_inter_block_reduce_scan( m_functor , blockIdx.x , gridDim.x , kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ); + // Reduce and scan, writing out scan of blocks' totals and block-groups' + // totals. Blocks' scan values are written to 'blockIdx.x' location. + // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < + // gridDim.x + cuda_single_inter_block_reduce_scan( + m_functor, blockIdx.x, gridDim.x, + kokkos_impl_cuda_shared_memory(), m_scratch_space, + m_scratch_flags); } //---------------------------------------- - __device__ inline - void final(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void final(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , value[2] , ... } - size_type * const shared_data = kokkos_impl_cuda_shared_memory(); - size_type * const shared_prefix = shared_data + word_count.value * threadIdx.y ; - size_type * const shared_accum = shared_data + word_count.value * ( blockDim.y + 1 ); + // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , + // value[2] , ... } + size_type* const shared_data = kokkos_impl_cuda_shared_memory(); + size_type* const shared_prefix = + shared_data + word_count.value * threadIdx.y; + size_type* const shared_accum = + shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. - if ( blockIdx.x ) { - size_type * const block_total = m_scratch_space + word_count.value * ( blockIdx.x - 1 ); - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i] ; } - } - else if ( 0 == threadIdx.y ) { - ValueInit::init( m_functor , shared_accum ); + if (blockIdx.x) { + size_type* const block_total = + m_scratch_space + word_count.value * (blockIdx.x - 1); + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } + } else if (0 == threadIdx.y) { + ValueInit::init(m_functor, shared_accum); } - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( typename Policy::member_type iwork_base = range.begin(); iwork_base < range.end() ; iwork_base += blockDim.y ) { - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - unsigned MASK=KOKKOS_IMPL_CUDA_ACTIVEMASK; - #endif - const typename Policy::member_type iwork = iwork_base + threadIdx.y ; + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base += blockDim.y) { +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK + unsigned MASK = KOKKOS_IMPL_CUDA_ACTIVEMASK; +#endif + const typename Policy::member_type iwork = iwork_base + threadIdx.y; - __syncthreads(); // Don't overwrite previous iteration values until they are used + __syncthreads(); // Don't overwrite previous iteration values until they + // are used - ValueInit::init( m_functor , shared_prefix + word_count.value ); + ValueInit::init(m_functor, shared_prefix + word_count.value); - // Copy previous block's accumulation total into thread[0] prefix and inclusive scan value of this block - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { - shared_data[i + word_count.value] = shared_data[i] = shared_accum[i] ; + // Copy previous block's accumulation total into thread[0] prefix and + // inclusive scan value of this block + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_data[i + word_count.value] = shared_data[i] = shared_accum[i]; } - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK KOKKOS_IMPL_CUDA_SYNCWARP_MASK(MASK); - #else +#else KOKKOS_IMPL_CUDA_SYNCWARP; - #endif - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } // Protect against large scan values. +#endif + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } // Protect against large scan values. // Call functor to accumulate inclusive scan value for this work item - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix + word_count.value ) , false ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix + word_count.value), + false); } // Scan block values into locations shared_data[1..blockDim.y] - cuda_intra_block_reduce_scan( m_functor , typename ValueTraits::pointer_type(shared_data+word_count.value) ); + cuda_intra_block_reduce_scan( + m_functor, + typename ValueTraits::pointer_type(shared_data + word_count.value)); { - size_type * const block_total = shared_data + word_count.value * blockDim.y ; - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i]; } + size_type* const block_total = + shared_data + word_count.value * blockDim.y; + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } } // Call functor with exclusive scan value - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix ) , true ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix), true); } } } -public: - + public: //---------------------------------------- - __device__ inline - void operator()(void) const - { - if ( ! m_final ) { - initial(); - } - else { - final(); + __device__ inline void operator()(void) const { +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + typename ValueTraits::value_type value; + ValueInit::init(m_functor, (void*)&value); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); + + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base++) { + this->template exec_range(iwork_base, value, true); + } + } else { +#endif + if (!m_final) { + initial(); + } else { + final(); + } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif } // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 (16 warps) - // gridDim.x <= blockDim.y * blockDim.y - // - // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit testing - - unsigned n = CudaTraits::WarpSize * 4 ; - while ( n && unsigned(m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock) < cuda_single_inter_block_reduce_scan_shmem( f , n ) ) { n >>= 1 ; } - return n ; - } - - inline - void execute() - { - const int nwork = m_policy.end() - m_policy.begin(); - if ( nwork ) { - enum { GridMaxComputeCapability_2x = 0x0ffff }; + inline unsigned local_block_size(const FunctorType& f) { + // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 + // (16 warps) gridDim.x <= blockDim.y * blockDim.y + // + // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit + // testing + + unsigned n = CudaTraits::WarpSize * 4; + while (n && + unsigned(m_policy.space() + .impl_internal_space_instance() + ->m_maxShmemPerBlock) < + cuda_single_inter_block_reduce_scan_shmem(f, n)) { + n >>= 1; + } + return n; + } - const int block_size = local_block_size( m_functor ); + inline void execute() { + const int nwork = m_policy.end() - m_policy.begin(); + if (nwork) { + enum { GridMaxComputeCapability_2x = 0x0ffff }; - const int grid_max = - ( block_size * block_size ) < GridMaxComputeCapability_2x ? - ( block_size * block_size ) : GridMaxComputeCapability_2x ; + const int block_size = local_block_size(m_functor); - // At most 'max_grid' blocks: - const int max_grid = std::min( int(grid_max) , int(( nwork + block_size - 1 ) / block_size )); + const int grid_max = + (block_size * block_size) < GridMaxComputeCapability_2x + ? (block_size * block_size) + : GridMaxComputeCapability_2x; - // How much work per block: - const int work_per_block = ( nwork + max_grid - 1 ) / max_grid ; + // At most 'max_grid' blocks: + const int max_grid = + std::min(int(grid_max), int((nwork + block_size - 1) / block_size)); - // How many block are really needed for this much work: - const int grid_x = ( nwork + work_per_block - 1 ) / work_per_block ; + // How much work per block: + const int work_per_block = (nwork + max_grid - 1) / max_grid; - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( m_functor ) * grid_x ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) * 1 ); + // How many block are really needed for this much work: + const int grid_x = (nwork + work_per_block - 1) / work_per_block; - const dim3 grid( grid_x , 1 , 1 ); - const dim3 block( 1 , block_size , 1 ); // REQUIRED DIMENSIONS ( 1 , N , 1 ) - const int shmem = ValueTraits::value_size( m_functor ) * ( block_size + 2 ); + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(m_functor) * grid_x); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) * 1); - m_final = false ; - CudaParallelLaunch< ParallelScan, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + dim3 grid(grid_x, 1, 1); + dim3 block(1, block_size, 1); // REQUIRED DIMENSIONS ( 1 , N , 1 ) + const int shmem = ValueTraits::value_size(m_functor) * (block_size + 2); - m_final = true ; - CudaParallelLaunch< ParallelScan, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } else { +#endif + m_final = false; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif + m_final = true; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute } + } - ParallelScan( const FunctorType & arg_functor , - const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_final( false ) - { } + ParallelScan(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), + m_policy(arg_policy), + m_scratch_space(0), + m_scratch_flags(0), + m_final(false) +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + , + m_run_serial(Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) +#endif + { + } }; //---------------------------------------------------------------------------- -template< class FunctorType, class ReturnType, class ... Traits > -class ParallelScanWithTotal< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReturnType - , Kokkos::Cuda - > -{ -public: - typedef Kokkos::RangePolicy< Traits ... > Policy ; - -private: - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; - typedef typename Policy::WorkRange WorkRange ; - typedef typename Policy::launch_bounds LaunchBounds ; - - typedef Kokkos::Impl::FunctorValueTraits< FunctorType, WorkTag > ValueTraits ; - typedef Kokkos::Impl::FunctorValueInit< FunctorType, WorkTag > ValueInit ; - typedef Kokkos::Impl::FunctorValueOps< FunctorType, WorkTag > ValueOps ; - -public: - - typedef typename ValueTraits::pointer_type pointer_type ; - typedef typename ValueTraits::reference_type reference_type ; - typedef FunctorType functor_type ; - typedef Cuda::size_type size_type ; - -private: +template +class ParallelScanWithTotal, + ReturnType, Kokkos::Cuda> { + public: + typedef Kokkos::RangePolicy Policy; + + private: + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; + typedef typename Policy::WorkRange WorkRange; + typedef typename Policy::launch_bounds LaunchBounds; + + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef Kokkos::Impl::FunctorValueInit ValueInit; + typedef Kokkos::Impl::FunctorValueOps ValueOps; + public: + typedef typename ValueTraits::pointer_type pointer_type; + typedef typename ValueTraits::reference_type reference_type; + typedef FunctorType functor_type; + typedef Cuda::size_type size_type; + + private: // Algorithmic constraints: // (a) blockDim.y is a power of two // (b) blockDim.y == blockDim.z == 1 // (c) gridDim.x <= blockDim.y * blockDim.y // (d) gridDim.y == gridDim.z == 1 - const FunctorType m_functor ; - const Policy m_policy ; - size_type * m_scratch_space ; - size_type * m_scratch_flags ; - size_type m_final ; - ReturnType & m_returnvalue; + const FunctorType m_functor; + const Policy m_policy; + size_type* m_scratch_space; + size_type* m_scratch_flags; + size_type m_final; + ReturnType& m_returnvalue; +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + bool m_run_serial; +#endif - template< class TagType > + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(i, update, final_result); + } - template< class TagType > + template __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_range( const Member & i , reference_type update , const bool final_result ) const - { m_functor( TagType() , i , update , final_result ); } + typename std::enable_if::value>::type + exec_range(const Member& i, reference_type update, + const bool final_result) const { + m_functor(TagType(), i, update, final_result); + } //---------------------------------------- - __device__ inline - void initial(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void initial(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - size_type * const shared_value = kokkos_impl_cuda_shared_memory() + word_count.value * threadIdx.y ; + size_type* const shared_value = + kokkos_impl_cuda_shared_memory() + + word_count.value * threadIdx.y; - ValueInit::init( m_functor , shared_value ); + ValueInit::init(m_functor, shared_value); - // Number of blocks is bounded so that the reduction can be limited to two passes. - // Each thread block is given an approximately equal amount of work to perform. - // Accumulate the values for this block. - // The accumulation ordering does not match the final pass, but is arithmatically equivalent. + // Number of blocks is bounded so that the reduction can be limited to two + // passes. Each thread block is given an approximately equal amount of work + // to perform. Accumulate the values for this block. The accumulation + // ordering does not match the final pass, but is arithmatically equivalent. - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( Member iwork = range.begin() + threadIdx.y , iwork_end = range.end() ; - iwork < iwork_end ; iwork += blockDim.y ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_value ) , false ); + for (Member iwork = range.begin() + threadIdx.y, iwork_end = range.end(); + iwork < iwork_end; iwork += blockDim.y) { + this->template exec_range( + iwork, ValueOps::reference(shared_value), false); } - // Reduce and scan, writing out scan of blocks' totals and block-groups' totals. - // Blocks' scan values are written to 'blockIdx.x' location. - // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < gridDim.x - cuda_single_inter_block_reduce_scan( m_functor , blockIdx.x , gridDim.x , kokkos_impl_cuda_shared_memory() , m_scratch_space , m_scratch_flags ); + // Reduce and scan, writing out scan of blocks' totals and block-groups' + // totals. Blocks' scan values are written to 'blockIdx.x' location. + // Block-groups' scan values are at: i = ( j * blockDim.y - 1 ) for i < + // gridDim.x + cuda_single_inter_block_reduce_scan( + m_functor, blockIdx.x, gridDim.x, + kokkos_impl_cuda_shared_memory(), m_scratch_space, + m_scratch_flags); } //---------------------------------------- - __device__ inline - void final(void) const - { - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( m_functor ) / sizeof(size_type) ); + __device__ inline void final(void) const { + const integral_nonzero_constant + word_count(ValueTraits::value_size(m_functor) / sizeof(size_type)); - // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , value[2] , ... } - size_type * const shared_data = kokkos_impl_cuda_shared_memory(); - size_type * const shared_prefix = shared_data + word_count.value * threadIdx.y ; - size_type * const shared_accum = shared_data + word_count.value * ( blockDim.y + 1 ); + // Use shared memory as an exclusive scan: { 0 , value[0] , value[1] , + // value[2] , ... } + size_type* const shared_data = kokkos_impl_cuda_shared_memory(); + size_type* const shared_prefix = + shared_data + word_count.value * threadIdx.y; + size_type* const shared_accum = + shared_data + word_count.value * (blockDim.y + 1); // Starting value for this thread block is the previous block's total. - if ( blockIdx.x ) { - size_type * const block_total = m_scratch_space + word_count.value * ( blockIdx.x - 1 ); - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i] ; } - } - else if ( 0 == threadIdx.y ) { - ValueInit::init( m_functor , shared_accum ); + if (blockIdx.x) { + size_type* const block_total = + m_scratch_space + word_count.value * (blockIdx.x - 1); + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } + } else if (0 == threadIdx.y) { + ValueInit::init(m_functor, shared_accum); } - const WorkRange range( m_policy , blockIdx.x , gridDim.x ); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); - for ( typename Policy::member_type iwork_base = range.begin(); iwork_base < range.end() ; iwork_base += blockDim.y ) { - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - unsigned MASK=KOKKOS_IMPL_CUDA_ACTIVEMASK; - #endif + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base += blockDim.y) { +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK + unsigned MASK = KOKKOS_IMPL_CUDA_ACTIVEMASK; +#endif - const typename Policy::member_type iwork = iwork_base + threadIdx.y ; + const typename Policy::member_type iwork = iwork_base + threadIdx.y; - __syncthreads(); // Don't overwrite previous iteration values until they are used + __syncthreads(); // Don't overwrite previous iteration values until they + // are used - ValueInit::init( m_functor , shared_prefix + word_count.value ); + ValueInit::init(m_functor, shared_prefix + word_count.value); - // Copy previous block's accumulation total into thread[0] prefix and inclusive scan value of this block - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { - shared_data[i + word_count.value] = shared_data[i] = shared_accum[i] ; + // Copy previous block's accumulation total into thread[0] prefix and + // inclusive scan value of this block + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_data[i + word_count.value] = shared_data[i] = shared_accum[i]; } - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK +#ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK KOKKOS_IMPL_CUDA_SYNCWARP_MASK(MASK); - #else +#else KOKKOS_IMPL_CUDA_SYNCWARP; - #endif - if ( CudaTraits::WarpSize < word_count.value ) { __syncthreads(); } // Protect against large scan values. +#endif + if (CudaTraits::WarpSize < word_count.value) { + __syncthreads(); + } // Protect against large scan values. // Call functor to accumulate inclusive scan value for this work item - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix + word_count.value ) , false ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix + word_count.value), + false); } // Scan block values into locations shared_data[1..blockDim.y] - cuda_intra_block_reduce_scan( m_functor , typename ValueTraits::pointer_type(shared_data+word_count.value) ); + cuda_intra_block_reduce_scan( + m_functor, + typename ValueTraits::pointer_type(shared_data + word_count.value)); { - size_type * const block_total = shared_data + word_count.value * blockDim.y ; - for ( unsigned i = threadIdx.y ; i < word_count.value ; ++i ) { shared_accum[i] = block_total[i]; } + size_type* const block_total = + shared_data + word_count.value * blockDim.y; + for (unsigned i = threadIdx.y; i < word_count.value; ++i) { + shared_accum[i] = block_total[i]; + } } // Call functor with exclusive scan value - if ( iwork < range.end() ) { - this-> template exec_range< WorkTag >( iwork , ValueOps::reference( shared_prefix ) , true ); + if (iwork < range.end()) { + this->template exec_range( + iwork, ValueOps::reference(shared_prefix), true); } } } -public: - + public: //---------------------------------------- - __device__ inline - void operator()(void) const - { - if ( ! m_final ) { - initial(); - } - else { - final(); + __device__ inline void operator()(void) const { +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + typename ValueTraits::value_type value; + ValueInit::init(m_functor, (void*)&value); + const WorkRange range(m_policy, blockIdx.x, gridDim.x); + + for (typename Policy::member_type iwork_base = range.begin(); + iwork_base < range.end(); iwork_base++) { + this->template exec_range(iwork_base, value, true); + } + *((typename ValueTraits::value_type*)m_scratch_space) = value; + } else { +#endif + if (!m_final) { + initial(); + } else { + final(); + } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif } // Determine block size constrained by shared memory: - inline - unsigned local_block_size( const FunctorType & f ) - { - // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 (16 warps) - // gridDim.x <= blockDim.y * blockDim.y - // - // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit testing - - unsigned n = CudaTraits::WarpSize * 4 ; - while ( n && unsigned(m_policy.space().impl_internal_space_instance()->m_maxShmemPerBlock) < cuda_single_inter_block_reduce_scan_shmem( f , n ) ) { n >>= 1 ; } - return n ; - } - - inline - void execute() - { - const int nwork = m_policy.end() - m_policy.begin(); - if ( nwork ) { - enum { GridMaxComputeCapability_2x = 0x0ffff }; + inline unsigned local_block_size(const FunctorType& f) { + // blockDim.y must be power of two = 128 (4 warps) or 256 (8 warps) or 512 + // (16 warps) gridDim.x <= blockDim.y * blockDim.y + // + // 4 warps was 10% faster than 8 warps and 20% faster than 16 warps in unit + // testing + + unsigned n = CudaTraits::WarpSize * 4; + while (n && + unsigned(m_policy.space() + .impl_internal_space_instance() + ->m_maxShmemPerBlock) < + cuda_single_inter_block_reduce_scan_shmem(f, n)) { + n >>= 1; + } + return n; + } - const int block_size = local_block_size( m_functor ); + inline void execute() { + const int nwork = m_policy.end() - m_policy.begin(); + if (nwork) { + enum { GridMaxComputeCapability_2x = 0x0ffff }; - const int grid_max = - ( block_size * block_size ) < GridMaxComputeCapability_2x ? - ( block_size * block_size ) : GridMaxComputeCapability_2x ; + const int block_size = local_block_size(m_functor); - // At most 'max_grid' blocks: - const int max_grid = std::min( int(grid_max) , int(( nwork + block_size - 1 ) / block_size )); + const int grid_max = + (block_size * block_size) < GridMaxComputeCapability_2x + ? (block_size * block_size) + : GridMaxComputeCapability_2x; - // How much work per block: - const int work_per_block = ( nwork + max_grid - 1 ) / max_grid ; + // At most 'max_grid' blocks: + const int max_grid = + std::min(int(grid_max), int((nwork + block_size - 1) / block_size)); - // How many block are really needed for this much work: - const int grid_x = ( nwork + work_per_block - 1 ) / work_per_block ; + // How much work per block: + const int work_per_block = (nwork + max_grid - 1) / max_grid; - m_scratch_space = cuda_internal_scratch_space( m_policy.space(), ValueTraits::value_size( m_functor ) * grid_x ); - m_scratch_flags = cuda_internal_scratch_flags( m_policy.space(), sizeof(size_type) * 1 ); + // How many block are really needed for this much work: + const int grid_x = (nwork + work_per_block - 1) / work_per_block; - const dim3 grid( grid_x , 1 , 1 ); - const dim3 block( 1 , block_size , 1 ); // REQUIRED DIMENSIONS ( 1 , N , 1 ) - const int shmem = ValueTraits::value_size( m_functor ) * ( block_size + 2 ); + m_scratch_space = cuda_internal_scratch_space( + m_policy.space(), ValueTraits::value_size(m_functor) * grid_x); + m_scratch_flags = + cuda_internal_scratch_flags(m_policy.space(), sizeof(size_type) * 1); - m_final = false ; - CudaParallelLaunch< ParallelScanWithTotal, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute + dim3 grid(grid_x, 1, 1); + dim3 block(1, block_size, 1); // REQUIRED DIMENSIONS ( 1 , N , 1 ) + const int shmem = ValueTraits::value_size(m_functor) * (block_size + 2); - m_final = true ; - CudaParallelLaunch< ParallelScanWithTotal, LaunchBounds >( *this, grid, block, shmem , m_policy.space().impl_internal_space_instance() , false ); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) { + block = dim3(1, 1, 1); + grid = dim3(1, 1, 1); + } else { +#endif - const int size = ValueTraits::value_size( m_functor ); - DeepCopy( &m_returnvalue, m_scratch_space + (grid_x - 1)*size/sizeof(int), size ); + m_final = false; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION } +#endif + m_final = true; + CudaParallelLaunch( + *this, grid, block, shmem, + m_policy.space().impl_internal_space_instance(), + false); // copy to device and execute + + const int size = ValueTraits::value_size(m_functor); +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + if (m_run_serial) + DeepCopy(&m_returnvalue, m_scratch_space, size); + else +#endif + DeepCopy( + &m_returnvalue, m_scratch_space + (grid_x - 1) * size / sizeof(int), + size); } + } - ParallelScanWithTotal( const FunctorType & arg_functor , - const Policy & arg_policy , - ReturnType & arg_returnvalue ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_scratch_space( 0 ) - , m_scratch_flags( 0 ) - , m_final( false ) - , m_returnvalue( arg_returnvalue ) - { } + ParallelScanWithTotal(const FunctorType& arg_functor, + const Policy& arg_policy, ReturnType& arg_returnvalue) + : m_functor(arg_functor), + m_policy(arg_policy), + m_scratch_space(0), + m_scratch_flags(0), + m_final(false), + m_returnvalue(arg_returnvalue) +#ifdef KOKKOS_IMPL_DEBUG_CUDA_SERIAL_EXECUTION + , + m_run_serial(Kokkos::Impl::CudaInternal::cuda_use_serial_execution()) +#endif + { + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -2131,155 +2606,228 @@ public: namespace Kokkos { namespace Impl { - template< class FunctorType, class ExecPolicy, class ValueType , class Tag = typename ExecPolicy::work_tag> - struct CudaFunctorAdapter { - const FunctorType f; - typedef ValueType value_type; - CudaFunctorAdapter(const FunctorType& f_):f(f_) {} - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, l, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, l, m, val); - } - - __device__ inline - void operator() (typename ExecPolicy::work_tag, const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, const typename ExecPolicy::member_type& n, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals third argument type of FunctorType::operator() - f(typename ExecPolicy::work_tag(), i, j, k, l, m, n, val); - } +template +struct CudaFunctorAdapter { + const FunctorType f; + typedef ValueType value_type; + CudaFunctorAdapter(const FunctorType& f_) : f(f_) {} + + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, val); + } - }; + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, val); + } - template< class FunctorType, class ExecPolicy, class ValueType > - struct CudaFunctorAdapter { - const FunctorType f; - typedef ValueType value_type; - CudaFunctorAdapter(const FunctorType& f_):f(f_) {} + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,val); - } + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, l, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,val); - } + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, l, m, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,val); - } + __device__ inline void operator()(typename ExecPolicy::work_tag, + const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + const typename ExecPolicy::member_type& n, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals third argument + // type of FunctorType::operator() + f(typename ExecPolicy::work_tag(), i, j, k, l, m, n, val); + } +}; - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,val); - } +template +struct CudaFunctorAdapter { + const FunctorType f; + typedef ValueType value_type; + CudaFunctorAdapter(const FunctorType& f_) : f(f_) {} + + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, val); + } - __device__ inline - void operator() (const typename ExecPolicy::member_type& i, const typename ExecPolicy::member_type& j, const typename ExecPolicy::member_type& k, const typename ExecPolicy::member_type& l, const typename ExecPolicy::member_type& m, const typename ExecPolicy::member_type& n, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,n,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, val); + } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,val); - } + __device__ inline void operator()(const typename ExecPolicy::member_type& i, + const typename ExecPolicy::member_type& j, + const typename ExecPolicy::member_type& k, + const typename ExecPolicy::member_type& l, + const typename ExecPolicy::member_type& m, + const typename ExecPolicy::member_type& n, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, n, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, typename ExecPolicy::member_type& l, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, typename ExecPolicy::member_type& l, typename ExecPolicy::member_type& m, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, val); + } - __device__ inline - void operator() (typename ExecPolicy::member_type& i, typename ExecPolicy::member_type& j, typename ExecPolicy::member_type& k, typename ExecPolicy::member_type& l, typename ExecPolicy::member_type& m, typename ExecPolicy::member_type& n, ValueType& val) const { - //Insert Static Assert with decltype on ValueType equals second argument type of FunctorType::operator() - f(i,j,k,l,m,n,val); - } + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + typename ExecPolicy::member_type& l, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, val); + } - }; + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + typename ExecPolicy::member_type& l, + typename ExecPolicy::member_type& m, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, val); + } - template::value > - struct FunctorReferenceType { - typedef ResultType& reference_type; - }; + __device__ inline void operator()(typename ExecPolicy::member_type& i, + typename ExecPolicy::member_type& j, + typename ExecPolicy::member_type& k, + typename ExecPolicy::member_type& l, + typename ExecPolicy::member_type& m, + typename ExecPolicy::member_type& n, + ValueType& val) const { + // Insert Static Assert with decltype on ValueType equals second argument + // type of FunctorType::operator() + f(i, j, k, l, m, n, val); + } +}; - template - struct FunctorReferenceType { - typedef typename Kokkos::Impl::FunctorValueTraits< FunctorType ,Tag >::reference_type reference_type; - }; +template ::value> +struct FunctorReferenceType { + typedef ResultType& reference_type; +}; - template< class FunctorTypeIn, class ExecPolicy, class ValueType> - struct ParallelReduceFunctorType { +template +struct FunctorReferenceType { + typedef typename Kokkos::Impl::FunctorValueTraits< + FunctorType, Tag>::reference_type reference_type; +}; - enum {FunctorHasValueType = IsNonTrivialReduceFunctor::value }; - typedef typename Kokkos::Impl::if_c >::type functor_type; - static functor_type functor(const FunctorTypeIn& functor_in) { - return Impl::if_c::select(functor_in,functor_type(functor_in)); - } +template +struct ParallelReduceFunctorType { + enum { + FunctorHasValueType = IsNonTrivialReduceFunctor::value }; + typedef typename Kokkos::Impl::if_c< + FunctorHasValueType, FunctorTypeIn, + Impl::CudaFunctorAdapter>::type + functor_type; + static functor_type functor(const FunctorTypeIn& functor_in) { + return Impl::if_c::select( + functor_in, functor_type(functor_in)); + } +}; -} +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos #endif /* defined( __CUDACC__ ) */ #endif /* #ifndef KOKKOS_CUDA_PARALLEL_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp index c39dddb198..41431bfb8d 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ReduceScan.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_REDUCESCAN_HPP #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include @@ -60,131 +61,6 @@ namespace Kokkos { namespace Impl { -//---------------------------------------------------------------------------- -// Shuffle operations require input to be a register (stack) variable - -// TODO: reconcile these implementations with those in Kokkos_Cuda_Vectorization.hpp - -template< typename T > -__device__ inline -void cuda_shfl( T & out , T const & in , int lane , - typename std::enable_if< sizeof(int) == sizeof(T) , int >::type width - , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_MASK( mask , *reinterpret_cast(&in) , lane , width ); -} - -// TODO: figure out why 64-bit shfl fails in Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - -template< typename T > -__device__ inline -void cuda_shfl( T & out , T const & in , int lane , - typename std::enable_if< sizeof(long long) == sizeof(T) , int >::type width - , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_MASK( mask , *reinterpret_cast(&in) , lane , width ); -} - -#endif - -template< typename T > -__device__ inline -void cuda_shfl( T & out , T const & in , int lane , - typename std::enable_if - < ( KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF < sizeof(T) ) && ( 0 == ( sizeof(T) % sizeof(int) ) ) - , int >::type width, unsigned mask = 0xffffffff ) -{ - enum : int { N = sizeof(T) / sizeof(int) }; - - for ( int i = 0 ; i < N ; ++i ) { - reinterpret_cast(&out)[i] = - KOKKOS_IMPL_CUDA_SHFL_MASK( mask , reinterpret_cast(&in)[i] , lane , width ); - } -} - -//---------------------------------------------------------------------------- - -template< typename T > -__device__ inline -void cuda_shfl_down( T & out , T const & in , int delta , - typename std::enable_if< sizeof(int) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -// TODO: figure out why 64-bit shfl fails in Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - -template< typename T > -__device__ inline -void cuda_shfl_down( T & out , T const & in , int delta , - typename std::enable_if< sizeof(long long) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -#endif - -template< typename T > -__device__ inline -void cuda_shfl_down( T & out , T const & in , int delta , - typename std::enable_if - < ( KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF < sizeof(T) ) && ( 0 == ( sizeof(T) % sizeof(int) ) ) - , int >::type width , unsigned mask = 0xffffffff ) -{ - enum : int { N = sizeof(T) / sizeof(int) }; - - for ( int i = 0 ; i < N ; ++i ) { - reinterpret_cast(&out)[i] = - KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK( mask , reinterpret_cast(&in)[i] , delta , width ); - } -} - -//---------------------------------------------------------------------------- - -template< typename T > -__device__ inline -void cuda_shfl_up( T & out , T const & in , int delta , - typename std::enable_if< sizeof(int) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_UP_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -// TODO: figure out why 64-bit shfl fails in Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - -template< typename T > -__device__ inline -void cuda_shfl_up( T & out , T const & in , int delta , - typename std::enable_if< sizeof(long long) == sizeof(T) , int >::type width , unsigned mask = 0xffffffff ) -{ - *reinterpret_cast(&out) = - KOKKOS_IMPL_CUDA_SHFL_UP_MASK( mask , *reinterpret_cast(&in) , delta , width ); -} - -#endif - -template< typename T > -__device__ inline -void cuda_shfl_up( T & out , T const & in , int delta , - typename std::enable_if - < ( KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF < sizeof(T) ) && ( 0 == ( sizeof(T) % sizeof(int) ) ) - , int >::type width , unsigned mask = 0xffffffff ) -{ - enum : int { N = sizeof(T) / sizeof(int) }; - - for ( int i = 0 ; i < N ; ++i ) { - reinterpret_cast(&out)[i] = - KOKKOS_IMPL_CUDA_SHFL_UP_MASK( mask , reinterpret_cast(&in)[i] , delta , width ); - } -} - //---------------------------------------------------------------------------- /* * Algorithmic constraints: @@ -193,511 +69,502 @@ void cuda_shfl_up( T & out , T const & in , int delta , * (c) blockDim.z == 1 */ -template< class ValueType , class JoinOp> +template __device__ inline -typename std::enable_if< !Kokkos::is_reducer::value >::type -cuda_intra_warp_reduction( ValueType& result, - const JoinOp& join, - const uint32_t max_active_thread = blockDim.y) { - + typename std::enable_if::value>::type + cuda_intra_warp_reduction(ValueType& result, const JoinOp& join, + const uint32_t max_active_thread = blockDim.y) { unsigned int shift = 1; - //Reduce over values from threads with different threadIdx.y - while(blockDim.x * shift < 32 ) { - const ValueType tmp = shfl_down(result, blockDim.x*shift,32u); - //Only join if upper thread is active (this allows non power of two for blockDim.y - if(threadIdx.y + shift < max_active_thread) - join(result , tmp); - shift*=2; + // Reduce over values from threads with different threadIdx.y + while (blockDim.x * shift < 32) { + const ValueType tmp = shfl_down(result, blockDim.x * shift, 32u); + // Only join if upper thread is active (this allows non power of two for + // blockDim.y + if (threadIdx.y + shift < max_active_thread) join(result, tmp); + shift *= 2; } - result = shfl(result,0,32); + result = shfl(result, 0, 32); } -template< class ValueType , class JoinOp> +template __device__ inline -typename std::enable_if< !Kokkos::is_reducer::value >::type -cuda_inter_warp_reduction( ValueType& value, - const JoinOp& join, - const int max_active_thread = blockDim.y) { - - #define STEP_WIDTH 4 - // Depending on the ValueType _shared__ memory must be aligned up to 8byte boundaries - // The reason not to use ValueType directly is that for types with constructors it - // could lead to race conditions - __shared__ double sh_result[(sizeof(ValueType)+7)/8*STEP_WIDTH]; - ValueType* result = (ValueType*) & sh_result; - const int step = 32 / blockDim.x; - int shift = STEP_WIDTH; - const int id = threadIdx.y%step==0?threadIdx.y/step:65000; - if(id < STEP_WIDTH ) { + typename std::enable_if::value>::type + cuda_inter_warp_reduction(ValueType& value, const JoinOp& join, + const int max_active_thread = blockDim.y) { +#define STEP_WIDTH 4 + // Depending on the ValueType _shared__ memory must be aligned up to 8byte + // boundaries The reason not to use ValueType directly is that for types with + // constructors it could lead to race conditions + __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; + ValueType* result = (ValueType*)&sh_result; + const int step = 32 / blockDim.x; + int shift = STEP_WIDTH; + const int id = threadIdx.y % step == 0 ? threadIdx.y / step : 65000; + if (id < STEP_WIDTH) { result[id] = value; } __syncthreads(); - while (shift<=max_active_thread/step) { - if(shift<=id && shift+STEP_WIDTH>id && threadIdx.x==0) { - join(result[id%STEP_WIDTH],value); + while (shift <= max_active_thread / step) { + if (shift <= id && shift + STEP_WIDTH > id && threadIdx.x == 0) { + join(result[id % STEP_WIDTH], value); } __syncthreads(); - shift+=STEP_WIDTH; + shift += STEP_WIDTH; } - value = result[0]; - for(int i = 1; (i*step +template __device__ inline -typename std::enable_if< !Kokkos::is_reducer::value >::type -cuda_intra_block_reduction( ValueType& value, - const JoinOp& join, - const int max_active_thread = blockDim.y) { - cuda_intra_warp_reduction(value,join,max_active_thread); - cuda_inter_warp_reduction(value,join,max_active_thread); + typename std::enable_if::value>::type + cuda_intra_block_reduction(ValueType& value, const JoinOp& join, + const int max_active_thread = blockDim.y) { + cuda_intra_warp_reduction(value, join, max_active_thread); + cuda_inter_warp_reduction(value, join, max_active_thread); } -template< class FunctorType , class JoinOp , class ArgTag = void > -__device__ -bool cuda_inter_block_reduction( typename FunctorValueTraits< FunctorType , ArgTag >::reference_type value, - typename FunctorValueTraits< FunctorType , ArgTag >::reference_type neutral, - const JoinOp& join, - Cuda::size_type * const m_scratch_space, - typename FunctorValueTraits< FunctorType , ArgTag >::pointer_type const result, - Cuda::size_type * const m_scratch_flags, - const int max_active_thread = blockDim.y) { +template +__device__ bool cuda_inter_block_reduction( + typename FunctorValueTraits::reference_type value, + typename FunctorValueTraits::reference_type neutral, + const JoinOp& join, Cuda::size_type* const m_scratch_space, + typename FunctorValueTraits::pointer_type const result, + Cuda::size_type* const m_scratch_flags, + const int max_active_thread = blockDim.y) { #ifdef __CUDA_ARCH__ - typedef typename FunctorValueTraits< FunctorType , ArgTag >::pointer_type pointer_type; - typedef typename FunctorValueTraits< FunctorType , ArgTag >::value_type value_type; + typedef typename FunctorValueTraits::pointer_type + pointer_type; + typedef + typename FunctorValueTraits::value_type value_type; - //Do the intra-block reduction with shfl operations and static shared memory - cuda_intra_block_reduction(value,join,max_active_thread); + // Do the intra-block reduction with shfl operations and static shared memory + cuda_intra_block_reduction(value, join, max_active_thread); - const int id = threadIdx.y*blockDim.x + threadIdx.x; + const int id = threadIdx.y * blockDim.x + threadIdx.x; - //One thread in the block writes block result to global scratch_memory - if(id == 0 ) { - pointer_type global = ((pointer_type) m_scratch_space) + blockIdx.x; - *global = value; + // One thread in the block writes block result to global scratch_memory + if (id == 0) { + pointer_type global = ((pointer_type)m_scratch_space) + blockIdx.x; + *global = value; } - //One warp of last block performs inter block reduction through loading the block values from global scratch_memory + // One warp of last block performs inter block reduction through loading the + // block values from global scratch_memory bool last_block = false; - + __threadfence(); __syncthreads(); - if ( id < 32 ) { + if (id < 32) { Cuda::size_type count; - //Figure out whether this is the last block - if(id == 0) - count = Kokkos::atomic_fetch_add(m_scratch_flags,1); - count = Kokkos::shfl(count,0,32); + // Figure out whether this is the last block + if (id == 0) count = Kokkos::atomic_fetch_add(m_scratch_flags, 1); + count = Kokkos::shfl(count, 0, 32); - //Last block does the inter block reduction - if( count == gridDim.x - 1) { - //set flag back to zero - if(id == 0) - *m_scratch_flags = 0; + // Last block does the inter block reduction + if (count == gridDim.x - 1) { + // set flag back to zero + if (id == 0) *m_scratch_flags = 0; last_block = true; - value = neutral; + value = neutral; - pointer_type const volatile global = (pointer_type) m_scratch_space ; + pointer_type const volatile global = (pointer_type)m_scratch_space; - //Reduce all global values with splitting work over threads in one warp - const int step_size = blockDim.x*blockDim.y < 32 ? blockDim.x*blockDim.y : 32; - for(int i=id; i<(int)gridDim.x; i+=step_size) { + // Reduce all global values with splitting work over threads in one warp + const int step_size = + blockDim.x * blockDim.y < 32 ? blockDim.x * blockDim.y : 32; + for (int i = id; i < (int)gridDim.x; i += step_size) { value_type tmp = global[i]; join(value, tmp); } - //Perform shfl reductions within the warp only join if contribution is valid (allows gridDim.x non power of two and <32) - if (int(blockDim.x*blockDim.y) > 1) { - value_type tmp = Kokkos::shfl_down(value, 1,32); - if( id + 1 < int(gridDim.x) ) - join(value, tmp); + // Perform shfl reductions within the warp only join if contribution is + // valid (allows gridDim.x non power of two and <32) + if (int(blockDim.x * blockDim.y) > 1) { + value_type tmp = Kokkos::shfl_down(value, 1, 32); + if (id + 1 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK unsigned int mask = KOKKOS_IMPL_CUDA_ACTIVEMASK; - int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else int active = KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 2) { - value_type tmp = Kokkos::shfl_down(value, 2,32); - if( id + 2 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 2) { + value_type tmp = Kokkos::shfl_down(value, 2, 32); + if (id + 2 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 4) { - value_type tmp = Kokkos::shfl_down(value, 4,32); - if( id + 4 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 4) { + value_type tmp = Kokkos::shfl_down(value, 4, 32); + if (id + 4 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 8) { - value_type tmp = Kokkos::shfl_down(value, 8,32); - if( id + 8 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 8) { + value_type tmp = Kokkos::shfl_down(value, 8, 32); + if (id + 8 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 16) { - value_type tmp = Kokkos::shfl_down(value, 16,32); - if( id + 16 < int(gridDim.x) ) - join(value, tmp); + if (int(blockDim.x * blockDim.y) > 16) { + value_type tmp = Kokkos::shfl_down(value, 16, 32); + if (id + 16 < int(gridDim.x)) join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif } } - //The last block has in its thread=0 the global reduction value through "value" + // The last block has in its thread=0 the global reduction value through + // "value" return last_block; #else return true; #endif } -template< class ReducerType > +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_intra_warp_reduction( const ReducerType& reducer, - typename ReducerType::value_type& result, - const uint32_t max_active_thread = blockDim.y) { - + typename std::enable_if::value>::type + cuda_intra_warp_reduction(const ReducerType& reducer, + typename ReducerType::value_type& result, + const uint32_t max_active_thread = blockDim.y) { typedef typename ReducerType::value_type ValueType; unsigned int shift = 1; - //Reduce over values from threads with different threadIdx.y - while(blockDim.x * shift < 32 ) { - const ValueType tmp = shfl_down(result, blockDim.x*shift,32u); - //Only join if upper thread is active (this allows non power of two for blockDim.y - if(threadIdx.y + shift < max_active_thread) - reducer.join(result , tmp); - shift*=2; + // Reduce over values from threads with different threadIdx.y + while (blockDim.x * shift < 32) { + const ValueType tmp = shfl_down(result, blockDim.x * shift, 32u); + // Only join if upper thread is active (this allows non power of two for + // blockDim.y + if (threadIdx.y + shift < max_active_thread) reducer.join(result, tmp); + shift *= 2; } - result = shfl(result,0,32); + result = shfl(result, 0, 32); reducer.reference() = result; } -template< class ReducerType > +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_inter_warp_reduction( const ReducerType& reducer, - typename ReducerType::value_type value, - const int max_active_thread = blockDim.y) { - + typename std::enable_if::value>::type + cuda_inter_warp_reduction(const ReducerType& reducer, + typename ReducerType::value_type value, + const int max_active_thread = blockDim.y) { typedef typename ReducerType::value_type ValueType; - #define STEP_WIDTH 4 - // Depending on the ValueType _shared__ memory must be aligned up to 8byte boundaries - // The reason not to use ValueType directly is that for types with constructors it - // could lead to race conditions - __shared__ double sh_result[(sizeof(ValueType)+7)/8*STEP_WIDTH]; - ValueType* result = (ValueType*) & sh_result; - const int step = 32 / blockDim.x; - int shift = STEP_WIDTH; - const int id = threadIdx.y%step==0?threadIdx.y/step:65000; - if(id < STEP_WIDTH ) { +#define STEP_WIDTH 4 + // Depending on the ValueType _shared__ memory must be aligned up to 8byte + // boundaries The reason not to use ValueType directly is that for types with + // constructors it could lead to race conditions + __shared__ double sh_result[(sizeof(ValueType) + 7) / 8 * STEP_WIDTH]; + ValueType* result = (ValueType*)&sh_result; + const int step = 32 / blockDim.x; + int shift = STEP_WIDTH; + const int id = threadIdx.y % step == 0 ? threadIdx.y / step : 65000; + if (id < STEP_WIDTH) { result[id] = value; } __syncthreads(); - while (shift<=max_active_thread/step) { - if(shift<=id && shift+STEP_WIDTH>id && threadIdx.x==0) { - reducer.join(result[id%STEP_WIDTH],value); + while (shift <= max_active_thread / step) { + if (shift <= id && shift + STEP_WIDTH > id && threadIdx.x == 0) { + reducer.join(result[id % STEP_WIDTH], value); } __syncthreads(); - shift+=STEP_WIDTH; + shift += STEP_WIDTH; } - value = result[0]; - for(int i = 1; (i*step +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_intra_block_reduction( const ReducerType& reducer, - typename ReducerType::value_type value, - const int max_active_thread = blockDim.y) { - cuda_intra_warp_reduction(reducer,value,max_active_thread); - cuda_inter_warp_reduction(reducer,value,max_active_thread); + typename std::enable_if::value>::type + cuda_intra_block_reduction(const ReducerType& reducer, + typename ReducerType::value_type value, + const int max_active_thread = blockDim.y) { + cuda_intra_warp_reduction(reducer, value, max_active_thread); + cuda_inter_warp_reduction(reducer, value, max_active_thread); } -template< class ReducerType > +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value >::type -cuda_intra_block_reduction( const ReducerType& reducer, - const int max_active_thread = blockDim.y) { - cuda_intra_block_reduction(reducer,reducer.reference(),max_active_thread); + typename std::enable_if::value>::type + cuda_intra_block_reduction(const ReducerType& reducer, + const int max_active_thread = blockDim.y) { + cuda_intra_block_reduction(reducer, reducer.reference(), max_active_thread); } -template< class ReducerType> +template __device__ inline -typename std::enable_if< Kokkos::is_reducer::value , bool >::type -cuda_inter_block_reduction( const ReducerType& reducer, - Cuda::size_type * const m_scratch_space, - Cuda::size_type * const m_scratch_flags, - const int max_active_thread = blockDim.y) { + typename std::enable_if::value, bool>::type + cuda_inter_block_reduction(const ReducerType& reducer, + Cuda::size_type* const m_scratch_space, + Cuda::size_type* const m_scratch_flags, + const int max_active_thread = blockDim.y) { #ifdef __CUDA_ARCH__ typedef typename ReducerType::value_type* pointer_type; typedef typename ReducerType::value_type value_type; - //Do the intra-block reduction with shfl operations and static shared memory - cuda_intra_block_reduction(reducer,max_active_thread); + // Do the intra-block reduction with shfl operations and static shared memory + cuda_intra_block_reduction(reducer, max_active_thread); value_type value = reducer.reference(); - const int id = threadIdx.y*blockDim.x + threadIdx.x; + const int id = threadIdx.y * blockDim.x + threadIdx.x; - //One thread in the block writes block result to global scratch_memory - if(id == 0 ) { - pointer_type global = ((pointer_type) m_scratch_space) + blockIdx.x; - *global = value; + // One thread in the block writes block result to global scratch_memory + if (id == 0) { + pointer_type global = ((pointer_type)m_scratch_space) + blockIdx.x; + *global = value; } - //One warp of last block performs inter block reduction through loading the block values from global scratch_memory + // One warp of last block performs inter block reduction through loading the + // block values from global scratch_memory bool last_block = false; + __threadfence(); __syncthreads(); - if ( id < 32 ) { + if (id < 32) { Cuda::size_type count; - //Figure out whether this is the last block - if(id == 0) - count = Kokkos::atomic_fetch_add(m_scratch_flags,1); - count = Kokkos::shfl(count,0,32); + // Figure out whether this is the last block + if (id == 0) count = Kokkos::atomic_fetch_add(m_scratch_flags, 1); + count = Kokkos::shfl(count, 0, 32); - //Last block does the inter block reduction - if( count == gridDim.x - 1) { - //set flag back to zero - if(id == 0) - *m_scratch_flags = 0; + // Last block does the inter block reduction + if (count == gridDim.x - 1) { + // set flag back to zero + if (id == 0) *m_scratch_flags = 0; last_block = true; reducer.init(value); - pointer_type const volatile global = (pointer_type) m_scratch_space ; + pointer_type const volatile global = (pointer_type)m_scratch_space; - //Reduce all global values with splitting work over threads in one warp - const int step_size = blockDim.x*blockDim.y < 32 ? blockDim.x*blockDim.y : 32; - for(int i=id; i<(int)gridDim.x; i+=step_size) { + // Reduce all global values with splitting work over threads in one warp + const int step_size = + blockDim.x * blockDim.y < 32 ? blockDim.x * blockDim.y : 32; + for (int i = id; i < (int)gridDim.x; i += step_size) { value_type tmp = global[i]; reducer.join(value, tmp); } - //Perform shfl reductions within the warp only join if contribution is valid (allows gridDim.x non power of two and <32) - if (int(blockDim.x*blockDim.y) > 1) { - value_type tmp = Kokkos::shfl_down(value, 1,32); - if( id + 1 < int(gridDim.x) ) - reducer.join(value, tmp); + // Perform shfl reductions within the warp only join if contribution is + // valid (allows gridDim.x non power of two and <32) + if (int(blockDim.x * blockDim.y) > 1) { + value_type tmp = Kokkos::shfl_down(value, 1, 32); + if (id + 1 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK unsigned int mask = KOKKOS_IMPL_CUDA_ACTIVEMASK; - int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + int active = KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else int active = KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 2) { - value_type tmp = Kokkos::shfl_down(value, 2,32); - if( id + 2 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 2) { + value_type tmp = Kokkos::shfl_down(value, 2, 32); + if (id + 2 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 4) { - value_type tmp = Kokkos::shfl_down(value, 4,32); - if( id + 4 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 4) { + value_type tmp = Kokkos::shfl_down(value, 4, 32); + if (id + 4 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 8) { - value_type tmp = Kokkos::shfl_down(value, 8,32); - if( id + 8 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 8) { + value_type tmp = Kokkos::shfl_down(value, 8, 32); + if (id + 8 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif - if (int(blockDim.x*blockDim.y) > 16) { - value_type tmp = Kokkos::shfl_down(value, 16,32); - if( id + 16 < int(gridDim.x) ) - reducer.join(value, tmp); + if (int(blockDim.x * blockDim.y) > 16) { + value_type tmp = Kokkos::shfl_down(value, 16, 32); + if (id + 16 < int(gridDim.x)) reducer.join(value, tmp); } #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask,1); + active += KOKKOS_IMPL_CUDA_BALLOT_MASK(mask, 1); #else active += KOKKOS_IMPL_CUDA_BALLOT(1); #endif } } - //The last block has in its thread=0 the global reduction value through "value" + // The last block has in its thread=0 the global reduction value through + // "value" return last_block; #else return true; #endif } -template +template struct CudaReductionsFunctor; -template +template struct CudaReductionsFunctor { - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; - typedef FunctorValueInit< FunctorType , ArgTag > ValueInit ; - typedef FunctorValueOps< FunctorType , ArgTag > ValueOps ; - typedef typename ValueTraits::pointer_type pointer_type ; + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; + typedef FunctorValueInit ValueInit; + typedef FunctorValueOps ValueOps; + typedef typename ValueTraits::pointer_type pointer_type; typedef typename ValueTraits::value_type Scalar; - __device__ - static inline void scalar_intra_warp_reduction( + __device__ static inline void scalar_intra_warp_reduction( const FunctorType& functor, - Scalar value, // Contribution - const bool skip_vector, // Skip threads if Kokkos vector lanes are not part of the reduction - const int width, // How much of the warp participates - Scalar& result) - { - unsigned mask = width==32?0xffffffff:((1<=w && warp_id= w && warp_id < w + shared_elements) { + if ((threadIdx.y * blockDim.x + threadIdx.x) % 32 == 0) + ValueJoin::join(functor, my_shared_team_buffer_element, &value); } __syncthreads(); } - - if( warp_id == 0) { - ValueInit::init( functor , &value ); - for(unsigned int i=threadIdx.y*blockDim.x+threadIdx.x; i +template struct CudaReductionsFunctor { - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; - typedef FunctorValueInit< FunctorType , ArgTag > ValueInit ; - typedef FunctorValueOps< FunctorType , ArgTag > ValueOps ; - typedef typename ValueTraits::pointer_type pointer_type ; + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; + typedef FunctorValueInit ValueInit; + typedef FunctorValueOps ValueOps; + typedef typename ValueTraits::pointer_type pointer_type; typedef typename ValueTraits::value_type Scalar; - __device__ - static inline void scalar_intra_warp_reduction( + __device__ static inline void scalar_intra_warp_reduction( const FunctorType& functor, - Scalar* value, // Contribution - const bool skip_vector, // Skip threads if Kokkos vector lanes are not part of the reduction - const int width) // How much of the warp participates + Scalar* value, // Contribution + const bool skip_vector, // Skip threads if Kokkos vector lanes are not + // part of the reduction + const int width) // How much of the warp participates { #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - unsigned mask = width==32?0xffffffff:((1< { KOKKOS_IMPL_CUDA_SYNCWARP; #endif } - *value=*(value-lane_id); + *value = *(value - lane_id); } - - __device__ - static inline void scalar_intra_block_reduction( - const FunctorType& functor, - Scalar value, - const bool skip, - Scalar* result, - const int shared_elements, - Scalar* shared_team_buffer_element) { - - const int warp_id = (threadIdx.y*blockDim.x)/32; + __device__ static inline void scalar_intra_block_reduction( + const FunctorType& functor, Scalar value, const bool skip, Scalar* result, + const int shared_elements, Scalar* shared_team_buffer_element) { + const int warp_id = (threadIdx.y * blockDim.x) / 32; Scalar* const my_shared_team_buffer_element = - shared_team_buffer_element + threadIdx.y*blockDim.x+threadIdx.x; + shared_team_buffer_element + threadIdx.y * blockDim.x + threadIdx.x; *my_shared_team_buffer_element = value; // Warp Level Reduction, ignoring Kokkos vector entries - scalar_intra_warp_reduction(functor,my_shared_team_buffer_element,skip,32); - // Wait for every warp to be done before using one warp to do final cross warp reduction + scalar_intra_warp_reduction(functor, my_shared_team_buffer_element, skip, + 32); + // Wait for every warp to be done before using one warp to do final cross + // warp reduction __syncthreads(); - if( warp_id == 0) { - const unsigned int delta = (threadIdx.y*blockDim.x+threadIdx.x)*32; - if(delta { * (c) blockDim.x == blockDim.z == 1 */ -template< bool DoScan , class FunctorType , class ArgTag > -__device__ -void cuda_intra_block_reduce_scan( const FunctorType & functor , - const typename FunctorValueTraits< FunctorType , ArgTag >::pointer_type base_data ) -{ - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; +template +__device__ void cuda_intra_block_reduce_scan( + const FunctorType& functor, + const typename FunctorValueTraits::pointer_type + base_data) { + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; - typedef typename ValueTraits::pointer_type pointer_type ; + typedef typename ValueTraits::pointer_type pointer_type; - const unsigned value_count = ValueTraits::value_count( functor ); - const unsigned BlockSizeMask = blockDim.y - 1 ; + const unsigned value_count = ValueTraits::value_count(functor); + const unsigned BlockSizeMask = blockDim.y - 1; // Must have power of two thread count - if ( BlockSizeMask & blockDim.y ) { Kokkos::abort("Cuda::cuda_intra_block_scan requires power-of-two blockDim"); } + if (BlockSizeMask & blockDim.y) { + Kokkos::abort("Cuda::cuda_intra_block_scan requires power-of-two blockDim"); + } -#define BLOCK_REDUCE_STEP( R , TD , S ) \ - if ( ! ( R & ((1<<(S+1))-1) ) ) { ValueJoin::join( functor , TD , (TD - (value_count< -__device__ -bool cuda_single_inter_block_reduce_scan2( const FunctorType & functor , - const Cuda::size_type block_id , - const Cuda::size_type block_count , - Cuda::size_type * const shared_data , - Cuda::size_type * const global_data , - Cuda::size_type * const global_flags ) -{ - typedef Cuda::size_type size_type ; - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - typedef FunctorValueJoin< FunctorType , ArgTag > ValueJoin ; - typedef FunctorValueInit< FunctorType , ArgTag > ValueInit ; - typedef FunctorValueOps< FunctorType , ArgTag > ValueOps ; - - typedef typename ValueTraits::pointer_type pointer_type ; +template +__device__ bool cuda_single_inter_block_reduce_scan2( + const FunctorType& functor, const Cuda::size_type block_id, + const Cuda::size_type block_count, Cuda::size_type* const shared_data, + Cuda::size_type* const global_data, Cuda::size_type* const global_flags) { + typedef Cuda::size_type size_type; + typedef FunctorValueTraits ValueTraits; + typedef FunctorValueJoin ValueJoin; + typedef FunctorValueInit ValueInit; + typedef FunctorValueOps ValueOps; + + typedef typename ValueTraits::pointer_type pointer_type; // '__ffs' = position of the least significant bit set to 1. // 'blockDim.y' is guaranteed to be a power of two so this // is the integral shift value that can replace an integral divide. - const unsigned BlockSizeShift = __ffs( blockDim.y ) - 1 ; - const unsigned BlockSizeMask = blockDim.y - 1 ; + const unsigned BlockSizeShift = __ffs(blockDim.y) - 1; + const unsigned BlockSizeMask = blockDim.y - 1; // Must have power of two thread count - if ( BlockSizeMask & blockDim.y ) { Kokkos::abort("Cuda::cuda_single_inter_block_reduce_scan requires power-of-two blockDim"); } + if (BlockSizeMask & blockDim.y) { + Kokkos::abort( + "Cuda::cuda_single_inter_block_reduce_scan requires power-of-two " + "blockDim"); + } - const integral_nonzero_constant< size_type , ValueTraits::StaticValueSize / sizeof(size_type) > - word_count( ValueTraits::value_size( functor ) / sizeof(size_type) ); + const integral_nonzero_constant + word_count(ValueTraits::value_size(functor) / sizeof(size_type)); // Reduce the accumulation for the entire block. - cuda_intra_block_reduce_scan( functor , pointer_type(shared_data) ); + cuda_intra_block_reduce_scan( + functor, pointer_type(shared_data)); { // Write accumulation total to global scratch space. // Accumulation total is the last thread's data. - size_type * const shared = shared_data + word_count.value * BlockSizeMask ; - size_type * const global = global_data + word_count.value * block_id ; + size_type* const shared = shared_data + word_count.value * BlockSizeMask; + size_type* const global = global_data + word_count.value * block_id; - for ( int i = int(threadIdx.y) ; i < int(word_count.value) ; i += int(blockDim.y) ) { global[i] = shared[i] ; } + for (int i = int(threadIdx.y); i < int(word_count.value); + i += int(blockDim.y)) { + global[i] = shared[i]; + } } - - // Contributing blocks note that their contribution has been completed via an atomic-increment flag - // If this block is not the last block to contribute to this group then the block is done. - const bool is_last_block = - ! __syncthreads_or( threadIdx.y ? 0 : ( 1 + atomicInc( global_flags , block_count - 1 ) < block_count ) ); - - if ( is_last_block ) { - - const size_type b = ( long(block_count) * long(threadIdx.y) ) >> BlockSizeShift ; - const size_type e = ( long(block_count) * long( threadIdx.y + 1 ) ) >> BlockSizeShift ; + __threadfence(); + + // Contributing blocks note that their contribution has been completed via an + // atomic-increment flag If this block is not the last block to contribute to + // this group then the block is done. + const bool is_last_block = !__syncthreads_or( + threadIdx.y + ? 0 + : (1 + atomicInc(global_flags, block_count - 1) < block_count)); + + if (is_last_block) { + const size_type b = + (long(block_count) * long(threadIdx.y)) >> BlockSizeShift; + const size_type e = + (long(block_count) * long(threadIdx.y + 1)) >> BlockSizeShift; { - void * const shared_ptr = shared_data + word_count.value * threadIdx.y ; - /* reference_type shared_value = */ ValueInit::init( functor , shared_ptr ); + void* const shared_ptr = shared_data + word_count.value * threadIdx.y; + /* reference_type shared_value = */ ValueInit::init(functor, shared_ptr); - for ( size_type i = b ; i < e ; ++i ) { - ValueJoin::join( functor , shared_ptr , global_data + word_count.value * i ); + for (size_type i = b; i < e; ++i) { + ValueJoin::join(functor, shared_ptr, + global_data + word_count.value * i); } } - cuda_intra_block_reduce_scan( functor , pointer_type(shared_data) ); + cuda_intra_block_reduce_scan( + functor, pointer_type(shared_data)); - if ( DoScan ) { + if (DoScan) { + size_type* const shared_value = + shared_data + + word_count.value * (threadIdx.y ? threadIdx.y - 1 : blockDim.y); - size_type * const shared_value = shared_data + word_count.value * ( threadIdx.y ? threadIdx.y - 1 : blockDim.y ); - - if ( ! threadIdx.y ) { ValueInit::init( functor , shared_value ); } + if (!threadIdx.y) { + ValueInit::init(functor, shared_value); + } // Join previous inclusive scan value to each member - for ( size_type i = b ; i < e ; ++i ) { - size_type * const global_value = global_data + word_count.value * i ; - ValueJoin::join( functor , shared_value , global_value ); - ValueOps ::copy( functor , global_value , shared_value ); + for (size_type i = b; i < e; ++i) { + size_type* const global_value = global_data + word_count.value * i; + ValueJoin::join(functor, shared_value, global_value); + ValueOps ::copy(functor, global_value, shared_value); } } } - return is_last_block ; + return is_last_block; } -template< bool DoScan , class FunctorType , class ArgTag > -__device__ -bool cuda_single_inter_block_reduce_scan( const FunctorType & functor , - const Cuda::size_type block_id , - const Cuda::size_type block_count , - Cuda::size_type * const shared_data , - Cuda::size_type * const global_data , - Cuda::size_type * const global_flags ) -{ - typedef FunctorValueTraits< FunctorType , ArgTag > ValueTraits ; - if(!DoScan && ValueTraits::StaticValueSize) - return Kokkos::Impl::CudaReductionsFunctor16)>::scalar_inter_block_reduction(functor,block_id,block_count,shared_data,global_data,global_flags); +template +__device__ bool cuda_single_inter_block_reduce_scan( + const FunctorType& functor, const Cuda::size_type block_id, + const Cuda::size_type block_count, Cuda::size_type* const shared_data, + Cuda::size_type* const global_data, Cuda::size_type* const global_flags) { + typedef FunctorValueTraits ValueTraits; + if (!DoScan && ValueTraits::StaticValueSize) + return Kokkos::Impl::CudaReductionsFunctor< + FunctorType, ArgTag, false, (ValueTraits::StaticValueSize > 16)>:: + scalar_inter_block_reduction(functor, block_id, block_count, + shared_data, global_data, global_flags); else - return cuda_single_inter_block_reduce_scan2(functor, block_id, block_count, shared_data, global_data, global_flags); + return cuda_single_inter_block_reduce_scan2( + functor, block_id, block_count, shared_data, global_data, global_flags); } // Size in bytes required for inter block reduce or scan -template< bool DoScan , class FunctorType , class ArgTag > -inline -unsigned cuda_single_inter_block_reduce_scan_shmem( const FunctorType & functor , const unsigned BlockSize ) -{ - return ( BlockSize + 2 ) * Impl::FunctorValueTraits< FunctorType , ArgTag >::value_size( functor ); +template +inline unsigned cuda_single_inter_block_reduce_scan_shmem( + const FunctorType& functor, const unsigned BlockSize) { + return (BlockSize + 2) * + Impl::FunctorValueTraits::value_size(functor); } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( __CUDACC__ ) */ #endif /* KOKKOS_CUDA_REDUCESCAN_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp index ac36cfd67e..777f57ced4 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -42,7 +43,7 @@ */ #include -#if defined( KOKKOS_ENABLE_CUDA ) && defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_CUDA) && defined(KOKKOS_ENABLE_TASKDAG) #include @@ -54,13 +55,18 @@ namespace Kokkos { namespace Impl { -template class TaskQueue< Kokkos::Cuda, Impl::default_tasking_memory_space_for_execution_space_t > ; -template class TaskQueueMultiple< Kokkos::Cuda, Impl::default_tasking_memory_space_for_execution_space_t > ; +template class TaskQueue< + Kokkos::Cuda, + Impl::default_tasking_memory_space_for_execution_space_t >; +template class TaskQueueMultiple< + Kokkos::Cuda, + Impl::default_tasking_memory_space_for_execution_space_t >; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- #else void KOKKOS_CORE_SRC_CUDA_KOKKOS_CUDA_TASK_PREVENT_LINK_ERROR() {} -#endif /* #if defined( KOKKOS_ENABLE_CUDA ) && defined( KOKKOS_ENABLE_TASKDAG ) */ - +#endif /* #if defined( KOKKOS_ENABLE_CUDA ) && defined( KOKKOS_ENABLE_TASKDAG \ + ) */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp index c35987e49e..237d2430d6 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Task.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_IMPL_CUDA_TASK_HPP #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -53,7 +54,7 @@ #include #include -#include // CUDA_SAFE_CALL +#include // CUDA_SAFE_CALL #include //---------------------------------------------------------------------------- @@ -62,65 +63,57 @@ namespace Kokkos { namespace Impl { namespace { -template< typename TaskType > -__global__ -void set_cuda_task_base_apply_function_pointer - ( typename TaskType::function_type * ptr, typename TaskType::destroy_type* dtor ) -{ - *ptr = TaskType::apply; +template +__global__ void set_cuda_task_base_apply_function_pointer( + typename TaskType::function_type* ptr, + typename TaskType::destroy_type* dtor) { + *ptr = TaskType::apply; *dtor = TaskType::destroy; } -template< typename Scheduler > -__global__ -void cuda_task_queue_execute( Scheduler scheduler, int32_t shmem_size ) { - TaskQueueSpecialization< Scheduler >::driver( std::move(scheduler) , shmem_size ); +template +__global__ void cuda_task_queue_execute(Scheduler scheduler, + int32_t shmem_size) { + TaskQueueSpecialization::driver(std::move(scheduler), shmem_size); } -} - -template class TaskExec ; +} // namespace -template -class TaskQueueSpecialization< - SimpleTaskScheduler -> -{ -public: +template +class TaskExec; - using scheduler_type = SimpleTaskScheduler; +template +class TaskQueueSpecialization> { + public: + using scheduler_type = SimpleTaskScheduler; using execution_space = Kokkos::Cuda; - using memory_space = Kokkos::CudaUVMSpace; - using member_type = TaskExec ; + using memory_space = Kokkos::CudaUVMSpace; + using member_type = TaskExec; enum : long { max_league_size = 16 }; enum : int { warps_per_block = 4 }; KOKKOS_INLINE_FUNCTION - static - void iff_single_thread_recursive_execute( scheduler_type const& ) {} + static void iff_single_thread_recursive_execute(scheduler_type const&) {} - static int get_max_team_count( - execution_space const& - ) { + static int get_max_team_count(execution_space const&) { return Kokkos::Impl::cuda_internal_multiprocessor_count() * warps_per_block; } - __device__ - static void driver(scheduler_type scheduler, int32_t shmem_per_warp) - { - using queue_type = typename scheduler_type::task_queue_type; + __device__ static void driver(scheduler_type scheduler, + int32_t shmem_per_warp) { + using queue_type = typename scheduler_type::task_queue_type; using task_base_type = typename scheduler_type::task_base_type; - using runnable_task_base_type = typename scheduler_type::runnable_task_base_type; - using scheduling_info_storage_type = - SchedulingInfoStorage< + using runnable_task_base_type = + typename scheduler_type::runnable_task_base_type; + using scheduling_info_storage_type = SchedulingInfoStorage< runnable_task_base_type, - typename scheduler_type::task_scheduling_info_type - >; + typename scheduler_type::task_scheduling_info_type>; extern __shared__ int32_t shmem_all[]; - int32_t* const warp_shmem = shmem_all + (threadIdx.z * shmem_per_warp) / sizeof(int32_t); + int32_t* const warp_shmem = + shmem_all + (threadIdx.z * shmem_per_warp) / sizeof(int32_t); task_base_type* const shared_memory_task_copy = (task_base_type*)warp_shmem; @@ -129,44 +122,47 @@ public: member_type single_exec(scheduler, warp_shmem, 1); member_type team_exec(scheduler, warp_shmem, blockDim.y); - auto& queue = scheduler.queue(); + auto& queue = scheduler.queue(); auto& team_scheduler = team_exec.scheduler(); auto current_task = OptionalRef(); // Loop until all queues are empty and no tasks in flight - while(not queue.is_done()) { - - if(warp_lane == 0) { // should be (?) same as team_exec.team_rank() == 0 + while (not queue.is_done()) { + if (warp_lane == 0) { // should be (?) same as team_exec.team_rank() == 0 // pop off a task - current_task = queue.pop_ready_task(team_scheduler.team_scheduler_info()); + current_task = + queue.pop_ready_task(team_scheduler.team_scheduler_info()); } // Broadcast task pointer: // Sync before the broadcast KOKKOS_IMPL_CUDA_SYNCWARP; - - // pretend it's an int* for shuffle purposes - ((int*) ¤t_task)[0] = KOKKOS_IMPL_CUDA_SHFL(((int*) ¤t_task)[0], 0, 32); - ((int*) ¤t_task)[1] = KOKKOS_IMPL_CUDA_SHFL(((int*) ¤t_task)[1], 0, 32); - if(current_task) { + // pretend it's an int* for shuffle purposes + ((int*)¤t_task)[0] = + KOKKOS_IMPL_CUDA_SHFL(((int*)¤t_task)[0], 0, 32); + ((int*)¤t_task)[1] = + KOKKOS_IMPL_CUDA_SHFL(((int*)¤t_task)[1], 0, 32); + if (current_task) { KOKKOS_ASSERT(!current_task->as_runnable_task().get_respawn_flag()); int32_t b = sizeof(scheduling_info_storage_type) / sizeof(int32_t); static_assert( - sizeof(scheduling_info_storage_type) % sizeof(int32_t) == 0, - "bad task size" - ); + sizeof(scheduling_info_storage_type) % sizeof(int32_t) == 0, + "bad task size"); int32_t const e = current_task->get_allocation_size() / sizeof(int32_t); - KOKKOS_ASSERT(current_task->get_allocation_size() % sizeof(int32_t) == 0); + KOKKOS_ASSERT(current_task->get_allocation_size() % sizeof(int32_t) == + 0); - int32_t volatile* const task_mem = (int32_t volatile*)current_task.get(); + int32_t volatile* const task_mem = + (int32_t volatile*)current_task.get(); - // do a coordinated copy of the task closure from global to shared memory: - for(int32_t i = warp_lane; i < e; i += CudaTraits::WarpSize) { + // do a coordinated copy of the task closure from global to shared + // memory: + for (int32_t i = warp_lane; i < e; i += CudaTraits::WarpSize) { warp_shmem[i] = task_mem[i]; } @@ -174,13 +170,12 @@ public: // writes are visible to all threads in the warp. KOKKOS_IMPL_CUDA_SYNCWARP; - if(shared_memory_task_copy->is_team_runnable()) { + if (shared_memory_task_copy->is_team_runnable()) { // Thread Team Task shared_memory_task_copy->as_runnable_task().run(team_exec); - } - else if(threadIdx.y == 0) { - // TODO @tasking @optimization DSH Change this to warp_lane == 0 when we allow blockDim.x to be more than 1 - // Single Thread Task + } else if (threadIdx.y == 0) { + // TODO @tasking @optimization DSH Change this to warp_lane == 0 when + // we allow blockDim.x to be more than 1 Single Thread Task shared_memory_task_copy->as_runnable_task().run(single_exec); } @@ -189,8 +184,8 @@ public: KOKKOS_IMPL_CUDA_SYNCWARP; - //if(warp_lane < b % CudaTraits::WarpSize) b += CudaTraits::WarpSize; - //b -= b % CudaTraits::WarpSize; + // if(warp_lane < b % CudaTraits::WarpSize) b += CudaTraits::WarpSize; + // b -= b % CudaTraits::WarpSize; // copy task closure from shared to global memory: for (int32_t i = b + warp_lane; i < e; i += CudaTraits::WarpSize) { @@ -203,17 +198,15 @@ public: KOKKOS_IMPL_CUDA_SYNCWARP; - if (warp_lane == 0) { // If respawn requested copy respawn data back to main memory - if(shared_memory_task_copy->as_runnable_task().get_respawn_flag()) { - if(shared_memory_task_copy->as_runnable_task().has_predecessor()) { + if (shared_memory_task_copy->as_runnable_task().get_respawn_flag()) { + if (shared_memory_task_copy->as_runnable_task().has_predecessor()) { // It's not necessary to make this a volatile write because // the next read of the predecessor is on this thread in complete, // and the predecessor is cleared there (using a volatile write) current_task->as_runnable_task().acquire_predecessor_from( - shared_memory_task_copy->as_runnable_task() - ); + shared_memory_task_copy->as_runnable_task()); } // It may not necessary to make this a volatile write, since the @@ -224,39 +217,35 @@ public: // where else the priority would be read after it is scheduled // by this thread; for now, we leave it volatile, but we should // benchmark the cost of this.) - current_task.as_volatile()->set_priority(shared_memory_task_copy->get_priority()); + current_task.as_volatile()->set_priority( + shared_memory_task_copy->get_priority()); // It's not necessary to make this a volatile write, since the // next read of it (if true) will be by this thread in `complete()`, // which will unset the flag (using volatile) once it has handled // the respawn current_task->as_runnable_task().set_respawn_flag(); - } - queue.complete( - (*std::move(current_task)).as_runnable_task(), - team_scheduler.team_scheduler_info() - ); + queue.complete((*std::move(current_task)).as_runnable_task(), + team_scheduler.team_scheduler_info()); } - } } } - static - void execute(scheduler_type const& scheduler) - { - const int shared_per_warp = 2048 ; + static void execute(scheduler_type const& scheduler) { + const int shared_per_warp = 2048; const dim3 grid(Kokkos::Impl::cuda_internal_multiprocessor_count(), 1, 1); const dim3 block(1, Kokkos::Impl::CudaTraits::WarpSize, warps_per_block); - const int shared_total = shared_per_warp * warps_per_block; + const int shared_total = shared_per_warp * warps_per_block; const cudaStream_t stream = nullptr; KOKKOS_ASSERT( - static_cast(grid.x * grid.y * grid.z * block.x * block.y * block.z) - == static_cast(get_max_team_count(scheduler.get_execution_space()) * Kokkos::Impl::CudaTraits::WarpSize) - ); + static_cast(grid.x * grid.y * grid.z * block.x * block.y * + block.z) == + static_cast(get_max_team_count(scheduler.get_execution_space()) * + Kokkos::Impl::CudaTraits::WarpSize)); auto& queue = scheduler.queue(); @@ -265,7 +254,8 @@ public: // Query the stack size, in bytes: size_t previous_stack_size = 0; - CUDA_SAFE_CALL(cudaDeviceGetLimit(&previous_stack_size, cudaLimitStackSize)); + CUDA_SAFE_CALL( + cudaDeviceGetLimit(&previous_stack_size, cudaLimitStackSize)); // If not large enough then set the stack size, in bytes: @@ -275,45 +265,45 @@ public: CUDA_SAFE_CALL(cudaDeviceSetLimit(cudaLimitStackSize, larger_stack_size)); } - cuda_task_queue_execute<<>>(scheduler, shared_per_warp); + cuda_task_queue_execute<<>>( + scheduler, shared_per_warp); CUDA_SAFE_CALL(cudaGetLastError()); CUDA_SAFE_CALL(cudaDeviceSynchronize()); if (previous_stack_size < larger_stack_size) { - CUDA_SAFE_CALL(cudaDeviceSetLimit(cudaLimitStackSize, previous_stack_size)); + CUDA_SAFE_CALL( + cudaDeviceSetLimit(cudaLimitStackSize, previous_stack_size)); } } template static - // TODO @tasking @optimiazation DSH specialize this for trivially destructible types - void - get_function_pointer( - typename TaskType::function_type& ptr, - typename TaskType::destroy_type& dtor - ) - { + // TODO @tasking @optimiazation DSH specialize this for trivially + // destructible types + void + get_function_pointer(typename TaskType::function_type& ptr, + typename TaskType::destroy_type& dtor) { using function_type = typename TaskType::function_type; - using destroy_type = typename TaskType::destroy_type; + using destroy_type = typename TaskType::destroy_type; // TODO @tasking @minor DSH make sure there aren't any alignment concerns? - void* storage = cuda_internal_scratch_unified( - Kokkos::Cuda(), - sizeof(function_type) + sizeof(destroy_type) - ); + void* storage = cuda_internal_scratch_unified( + Kokkos::Cuda(), sizeof(function_type) + sizeof(destroy_type)); function_type* ptr_ptr = (function_type*)storage; - destroy_type* dtor_ptr = (destroy_type*)((char*)storage + sizeof(function_type)); + destroy_type* dtor_ptr = + (destroy_type*)((char*)storage + sizeof(function_type)); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - set_cuda_task_base_apply_function_pointer<<<1,1>>>(ptr_ptr, dtor_ptr); + set_cuda_task_base_apply_function_pointer + <<<1, 1>>>(ptr_ptr, dtor_ptr); - CUDA_SAFE_CALL( cudaGetLastError() ); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaGetLastError()); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - ptr = *ptr_ptr; + ptr = *ptr_ptr; dtor = *dtor_ptr; } }; @@ -321,144 +311,133 @@ public: //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- -template +template class TaskQueueSpecializationConstrained< - Scheduler, - typename std::enable_if< - std::is_same::value - >::type -> -{ -public: - - using scheduler_type = Scheduler; + Scheduler, + typename std::enable_if::value>::type> { + public: + using scheduler_type = Scheduler; using execution_space = Kokkos::Cuda; - using memory_space = Kokkos::CudaUVMSpace; - using member_type = TaskExec ; + using memory_space = Kokkos::CudaUVMSpace; + using member_type = TaskExec; enum : long { max_league_size = 16 }; KOKKOS_INLINE_FUNCTION - static - void iff_single_thread_recursive_execute( scheduler_type const& ) {} + static void iff_single_thread_recursive_execute(scheduler_type const&) {} - __device__ - static void driver(scheduler_type scheduler, int32_t shmem_per_warp) - { - using queue_type = typename scheduler_type::queue_type; + __device__ static void driver(scheduler_type scheduler, + int32_t shmem_per_warp) { + using queue_type = typename scheduler_type::queue_type; using task_root_type = TaskBase; extern __shared__ int32_t shmem_all[]; - task_root_type* const end = (task_root_type *) task_root_type::EndTag ; + task_root_type* const end = (task_root_type*)task_root_type::EndTag; task_root_type* const no_more_tasks_sentinel = nullptr; - int32_t * const warp_shmem = - shmem_all + ( threadIdx.z * shmem_per_warp ) / sizeof(int32_t); + int32_t* const warp_shmem = + shmem_all + (threadIdx.z * shmem_per_warp) / sizeof(int32_t); - task_root_type * const task_shmem = (task_root_type *) warp_shmem ; + task_root_type* const task_shmem = (task_root_type*)warp_shmem; - const int warp_lane = threadIdx.x + threadIdx.y * blockDim.x ; + const int warp_lane = threadIdx.x + threadIdx.y * blockDim.x; member_type single_exec(scheduler, warp_shmem, 1); member_type team_exec(scheduler, warp_shmem, blockDim.y); auto& team_queue = team_exec.scheduler().queue(); - task_root_type * task_ptr = no_more_tasks_sentinel; + task_root_type* task_ptr = no_more_tasks_sentinel; // Loop until all queues are empty and no tasks in flight do { - // Each team lead attempts to acquire either a thread team task // or collection of single thread tasks for the team. - if ( 0 == warp_lane ) { - - if( *((volatile int *) & team_queue.m_ready_count) > 0 ) { + if (0 == warp_lane) { + if (*((volatile int*)&team_queue.m_ready_count) > 0) { task_ptr = end; // Attempt to acquire a task // Loop by priority and then type - for ( int i = 0 ; i < queue_type::NumQueue && end == task_ptr ; ++i ) { - for ( int j = 0 ; j < 2 && end == task_ptr ; ++j ) { - task_ptr = queue_type::pop_ready_task( & team_queue.m_ready[i][j] ); + for (int i = 0; i < queue_type::NumQueue && end == task_ptr; ++i) { + for (int j = 0; j < 2 && end == task_ptr; ++j) { + task_ptr = queue_type::pop_ready_task(&team_queue.m_ready[i][j]); } } - } - else { + } else { // returns nullptr if and only if all other queues have a ready // count of 0 also. Otherwise, returns a task from another queue // or `end` if one couldn't be popped task_ptr = team_queue.attempt_to_steal_task(); - #if 0 +#if 0 if(task != no_more_tasks_sentinel && task != end) { std::printf("task stolen on rank %d\n", team_exec.league_rank()); } - #endif +#endif } - } // Synchronize warp with memory fence before broadcasting task pointer: // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "A" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; // Broadcast task pointer: - ((int*) & task_ptr )[0] = KOKKOS_IMPL_CUDA_SHFL( ((int*) & task_ptr )[0] , 0 , 32 ); - ((int*) & task_ptr )[1] = KOKKOS_IMPL_CUDA_SHFL( ((int*) & task_ptr )[1] , 0 , 32 ); - - #if defined( KOKKOS_DEBUG ) - KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "TaskQueue CUDA task_ptr" ); - #endif + ((int*)&task_ptr)[0] = KOKKOS_IMPL_CUDA_SHFL(((int*)&task_ptr)[0], 0, 32); + ((int*)&task_ptr)[1] = KOKKOS_IMPL_CUDA_SHFL(((int*)&task_ptr)[1], 0, 32); - if ( 0 == task_ptr ) break ; // 0 == queue->m_ready_count +#if defined(KOKKOS_DEBUG) + KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN("TaskQueue CUDA task_ptr"); +#endif - if ( end != task_ptr ) { + if (0 == task_ptr) break; // 0 == queue->m_ready_count + if (end != task_ptr) { // Whole warp copy task's closure to/from shared memory. // Use all threads of warp for coalesced read/write. int32_t const b = sizeof(task_root_type) / sizeof(int32_t); - int32_t const e = *((int32_t volatile *)( & task_ptr->m_alloc_size )) / sizeof(int32_t); + int32_t const e = + *((int32_t volatile*)(&task_ptr->m_alloc_size)) / sizeof(int32_t); - int32_t volatile * const task_mem = (int32_t volatile *) task_ptr ; + int32_t volatile* const task_mem = (int32_t volatile*)task_ptr; KOKKOS_ASSERT(e * sizeof(int32_t) < shmem_per_warp); // copy task closure from global to shared memory: - for ( int32_t i = warp_lane ; i < e ; i += CudaTraits::WarpSize ) { - warp_shmem[i] = task_mem[i] ; + for (int32_t i = warp_lane; i < e; i += CudaTraits::WarpSize) { + warp_shmem[i] = task_mem[i]; } // Synchronize threads of the warp and insure memory // writes are visible to all threads in the warp. // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "B" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; - if ( task_root_type::TaskTeam == task_shmem->m_task_type ) { + if (task_root_type::TaskTeam == task_shmem->m_task_type) { // Thread Team Task - (*task_shmem->m_apply)( task_shmem , & team_exec ); - } - else if ( 0 == threadIdx.y ) { + (*task_shmem->m_apply)(task_shmem, &team_exec); + } else if (0 == threadIdx.y) { // Single Thread Task - (*task_shmem->m_apply)( task_shmem , & single_exec ); + (*task_shmem->m_apply)(task_shmem, &single_exec); } // Synchronize threads of the warp and insure memory // writes are visible to all threads in the warp. // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "C" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; // copy task closure from shared to global memory: - for ( int32_t i = b + warp_lane ; i < e ; i += CudaTraits::WarpSize ) { - task_mem[i] = warp_shmem[i] ; + for (int32_t i = b + warp_lane; i < e; i += CudaTraits::WarpSize) { + task_mem[i] = warp_shmem[i]; } // Synchronize threads of the warp and insure memory @@ -466,99 +445,96 @@ public: // respawn or completion. // KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( "D" ); - KOKKOS_IMPL_CUDA_SYNCWARP ; + KOKKOS_IMPL_CUDA_SYNCWARP; // If respawn requested copy respawn data back to main memory - if ( 0 == warp_lane ) { - - if ( ((task_root_type *) task_root_type::LockTag) != task_shmem->m_next ) { - ( (volatile task_root_type *) task_ptr )->m_next = task_shmem->m_next ; - ( (volatile task_root_type *) task_ptr )->m_priority = task_shmem->m_priority ; + if (0 == warp_lane) { + if (((task_root_type*)task_root_type::LockTag) != + task_shmem->m_next) { + ((volatile task_root_type*)task_ptr)->m_next = task_shmem->m_next; + ((volatile task_root_type*)task_ptr)->m_priority = + task_shmem->m_priority; } - team_queue.complete( task_ptr ); + team_queue.complete(task_ptr); } - } - } while(1); + } while (1); } - static - void execute(scheduler_type const& scheduler) - { - const int shared_per_warp = 2048 ; - const int warps_per_block = 4 ; - const dim3 grid( Kokkos::Impl::cuda_internal_multiprocessor_count() , 1 , 1 ); - //const dim3 grid( 1 , 1 , 1 ); - const dim3 block( 1 , Kokkos::Impl::CudaTraits::WarpSize , warps_per_block ); - const int shared_total = shared_per_warp * warps_per_block ; - const cudaStream_t stream = 0 ; + static void execute(scheduler_type const& scheduler) { + const int shared_per_warp = 2048; + const int warps_per_block = 4; + const dim3 grid(Kokkos::Impl::cuda_internal_multiprocessor_count(), 1, 1); + // const dim3 grid( 1 , 1 , 1 ); + const dim3 block(1, Kokkos::Impl::CudaTraits::WarpSize, warps_per_block); + const int shared_total = shared_per_warp * warps_per_block; + const cudaStream_t stream = 0; auto& queue = scheduler.queue(); queue.initialize_team_queues(warps_per_block * grid.x); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); // Query the stack size, in bytes: - size_t previous_stack_size = 0 ; - CUDA_SAFE_CALL( cudaDeviceGetLimit( & previous_stack_size , cudaLimitStackSize ) ); + size_t previous_stack_size = 0; + CUDA_SAFE_CALL( + cudaDeviceGetLimit(&previous_stack_size, cudaLimitStackSize)); // If not large enough then set the stack size, in bytes: - const size_t larger_stack_size = 2048 ; + const size_t larger_stack_size = 2048; - if ( previous_stack_size < larger_stack_size ) { - CUDA_SAFE_CALL( cudaDeviceSetLimit( cudaLimitStackSize , larger_stack_size ) ); + if (previous_stack_size < larger_stack_size) { + CUDA_SAFE_CALL(cudaDeviceSetLimit(cudaLimitStackSize, larger_stack_size)); } - cuda_task_queue_execute<<< grid , block , shared_total , stream >>>( scheduler , shared_per_warp ); + cuda_task_queue_execute<<>>( + scheduler, shared_per_warp); - CUDA_SAFE_CALL( cudaGetLastError() ); + CUDA_SAFE_CALL(cudaGetLastError()); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - if ( previous_stack_size < larger_stack_size ) { - CUDA_SAFE_CALL( cudaDeviceSetLimit( cudaLimitStackSize , previous_stack_size ) ); + if (previous_stack_size < larger_stack_size) { + CUDA_SAFE_CALL( + cudaDeviceSetLimit(cudaLimitStackSize, previous_stack_size)); } - } - template< typename TaskType > - static - void - get_function_pointer( - typename TaskType::function_type& ptr, - typename TaskType::destroy_type& dtor - ) - { - using function_type = typename TaskType::function_type; - using destroy_type = typename TaskType::destroy_type; - - void* storage = cuda_internal_scratch_unified( - Kokkos::Cuda(), - sizeof(function_type) + sizeof(destroy_type) - ); - function_type* ptr_ptr = (function_type*)storage; - destroy_type* dtor_ptr = (destroy_type*)((char*)storage + sizeof(function_type)); + template + static void get_function_pointer(typename TaskType::function_type& ptr, + typename TaskType::destroy_type& dtor) { + using function_type = typename TaskType::function_type; + using destroy_type = typename TaskType::destroy_type; - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + void* storage = cuda_internal_scratch_unified( + Kokkos::Cuda(), sizeof(function_type) + sizeof(destroy_type)); + function_type* ptr_ptr = (function_type*)storage; + destroy_type* dtor_ptr = + (destroy_type*)((char*)storage + sizeof(function_type)); - set_cuda_task_base_apply_function_pointer<<<1,1>>>(ptr_ptr, dtor_ptr); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - CUDA_SAFE_CALL( cudaGetLastError() ); - CUDA_SAFE_CALL( cudaDeviceSynchronize() ); + set_cuda_task_base_apply_function_pointer + <<<1, 1>>>(ptr_ptr, dtor_ptr); - ptr = *ptr_ptr; - dtor = *dtor_ptr; + CUDA_SAFE_CALL(cudaGetLastError()); + CUDA_SAFE_CALL(cudaDeviceSynchronize()); - } + ptr = *ptr_ptr; + dtor = *dtor_ptr; + } }; -extern template class TaskQueue< Kokkos::Cuda, default_tasking_memory_space_for_execution_space_t > ; +extern template class TaskQueue< + Kokkos::Cuda, + default_tasking_memory_space_for_execution_space_t>; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -589,85 +565,82 @@ namespace Impl { * warp synchronizing functions must not be called. */ template -class TaskExec -{ -private: - +class TaskExec { + private: enum : int { WarpSize = Kokkos::Impl::CudaTraits::WarpSize }; - TaskExec( TaskExec && ) = delete ; - TaskExec( TaskExec const & ) = delete ; - TaskExec & operator = ( TaskExec && ) = delete ; - TaskExec & operator = ( TaskExec const & ) = delete ; + TaskExec(TaskExec&&) = delete; + TaskExec(TaskExec const&) = delete; + TaskExec& operator=(TaskExec&&) = delete; + TaskExec& operator=(TaskExec const&) = delete; - friend class Kokkos::Impl::TaskQueue< Kokkos::Cuda, default_tasking_memory_space_for_execution_space_t > ; + friend class Kokkos::Impl::TaskQueue< + Kokkos::Cuda, + default_tasking_memory_space_for_execution_space_t>; template friend class Kokkos::Impl::TaskQueueSpecializationConstrained; template friend class Kokkos::Impl::TaskQueueSpecialization; - int32_t * m_team_shmem ; - const int m_team_size ; + int32_t* m_team_shmem; + const int m_team_size; Scheduler m_scheduler; // If constructed with arg_team_size == 1 the object // can only be used by 0 == threadIdx.y. KOKKOS_INLINE_FUNCTION - TaskExec( - Scheduler const& parent_scheduler, - int32_t* arg_team_shmem, - int arg_team_size = blockDim.y - ) - : m_team_shmem(arg_team_shmem), - m_team_size(arg_team_size), - m_scheduler(parent_scheduler.get_team_scheduler(league_rank())) - { } - -public: + TaskExec(Scheduler const& parent_scheduler, int32_t* arg_team_shmem, + int arg_team_size = blockDim.y) + : m_team_shmem(arg_team_shmem), + m_team_size(arg_team_size), + m_scheduler(parent_scheduler.get_team_scheduler(league_rank())) {} + public: using thread_team_member = TaskExec; -#if defined( __CUDA_ARCH__ ) - __device__ int team_rank() const { return threadIdx.y ; } - __device__ int team_size() const { return m_team_size ; } +#if defined(__CUDA_ARCH__) + __device__ int team_rank() const { return threadIdx.y; } + __device__ int team_size() const { return m_team_size; } //__device__ int league_rank() const { return threadIdx.z; } - __device__ int league_rank() const { return blockIdx.x * blockDim.z + threadIdx.z; } + __device__ int league_rank() const { + return blockIdx.x * blockDim.z + threadIdx.z; + } __device__ int league_size() const { return blockDim.z * gridDim.x; } - __device__ void team_barrier() const - { - if ( 1 < m_team_size ) { - KOKKOS_IMPL_CUDA_SYNCWARP ; - } + __device__ void team_barrier() const { + if (1 < m_team_size) { + KOKKOS_IMPL_CUDA_SYNCWARP; } + } - template< class ValueType > - __device__ void team_broadcast( ValueType & val , const int thread_id ) const - { - if ( 1 < m_team_size ) { - // WarpSize = blockDim.X * blockDim.y - // thread_id < blockDim.y - ValueType tmp( val ); // input might not be register variable - cuda_shfl( val, tmp, blockDim.x * thread_id, WarpSize ); - } + template + __device__ void team_broadcast(ValueType& val, const int thread_id) const { + if (1 < m_team_size) { + // WarpSize = blockDim.X * blockDim.y + // thread_id < blockDim.y + ValueType tmp(val); // input might not be register variable + Impl::in_place_shfl(val, tmp, blockDim.x * thread_id, WarpSize); } + } #else - __host__ int team_rank() const { return 0 ; } - __host__ int team_size() const { return 0 ; } + __host__ int team_rank() const { return 0; } + __host__ int team_size() const { return 0; } __host__ int league_rank() const { return 0; } __host__ int league_size() const { return 0; } __host__ void team_barrier() const {} - template< class ValueType > - __host__ void team_broadcast( ValueType & , const int ) const {} + template + __host__ void team_broadcast(ValueType&, const int) const {} #endif - KOKKOS_INLINE_FUNCTION Scheduler const& scheduler() const noexcept { return m_scheduler; } + KOKKOS_INLINE_FUNCTION Scheduler const& scheduler() const noexcept { + return m_scheduler; + } KOKKOS_INLINE_FUNCTION Scheduler& scheduler() noexcept { return m_scheduler; } - }; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -675,144 +648,137 @@ public: namespace Kokkos { namespace Impl { -template -struct TeamThreadRangeBoundariesStruct> -{ - using index_type = iType; +template +struct TeamThreadRangeBoundariesStruct> { + using index_type = iType; using member_type = TaskExec; - const iType start ; - const iType end ; - const iType increment ; + const iType start; + const iType end; + const iType increment; member_type const& thread; -#if defined( __CUDA_ARCH__ ) - - __device__ inline - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread, const iType& arg_count) - : start( threadIdx.y ) - , end(arg_count) - , increment( blockDim.y ) - , thread(arg_thread) - {} - - __device__ inline - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread - , const iType & arg_start - , const iType & arg_end - ) - : start( arg_start + threadIdx.y ) - , end( arg_end) - , increment( blockDim.y ) - , thread( arg_thread ) - {} +#if defined(__CUDA_ARCH__) + + __device__ inline TeamThreadRangeBoundariesStruct( + member_type const& arg_thread, const iType& arg_count) + : start(threadIdx.y), + end(arg_count), + increment(blockDim.y), + thread(arg_thread) {} + + __device__ inline TeamThreadRangeBoundariesStruct( + member_type const& arg_thread, const iType& arg_start, + const iType& arg_end) + : start(arg_start + threadIdx.y), + end(arg_end), + increment(blockDim.y), + thread(arg_thread) {} #else - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread, const iType& arg_count); + TeamThreadRangeBoundariesStruct(member_type const& arg_thread, + const iType& arg_count); - TeamThreadRangeBoundariesStruct - ( member_type const& arg_thread - , const iType & arg_start - , const iType & arg_end - ); + TeamThreadRangeBoundariesStruct(member_type const& arg_thread, + const iType& arg_start, const iType& arg_end); #endif - }; //---------------------------------------------------------------------------- -template -struct ThreadVectorRangeBoundariesStruct > -{ - using index_type = iType; +template +struct ThreadVectorRangeBoundariesStruct> { + using index_type = iType; using member_type = TaskExec; - const index_type start ; - const index_type end ; - const index_type increment ; + const index_type start; + const index_type end; + const index_type increment; const member_type& thread; -#if defined( __CUDA_ARCH__ ) - - __device__ inline - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_count ) - : start( threadIdx.x ) - , end(arg_count) - , increment( blockDim.x ) - , thread(arg_thread) - {} - - __device__ inline - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_begin, const index_type& arg_end ) - : start( arg_begin + threadIdx.x ) - , end(arg_end) - , increment( blockDim.x ) - , thread(arg_thread) - {} +#if defined(__CUDA_ARCH__) + + __device__ inline ThreadVectorRangeBoundariesStruct( + member_type const& arg_thread, const index_type& arg_count) + : start(threadIdx.x), + end(arg_count), + increment(blockDim.x), + thread(arg_thread) {} + + __device__ inline ThreadVectorRangeBoundariesStruct( + member_type const& arg_thread, const index_type& arg_begin, + const index_type& arg_end) + : start(arg_begin + threadIdx.x), + end(arg_end), + increment(blockDim.x), + thread(arg_thread) {} #else - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_count ); + ThreadVectorRangeBoundariesStruct(member_type const& arg_thread, + const index_type& arg_count); - ThreadVectorRangeBoundariesStruct - ( member_type const& arg_thread, const index_type& arg_begin, const index_type& arg_end); + ThreadVectorRangeBoundariesStruct(member_type const& arg_thread, + const index_type& arg_begin, + const index_type& arg_end); #endif - }; -}} /* namespace Kokkos::Impl */ +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -//template -//KOKKOS_INLINE_FUNCTION -//Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > > -//TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread, const iType & count ) +// template +// KOKKOS_INLINE_FUNCTION +// Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > +// > TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread, const iType +// & count ) //{ -// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > >( thread, count ); +// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< +// Kokkos::Cuda > >( thread, count ); //} // -//template -//KOKKOS_INLINE_FUNCTION -//Impl::TeamThreadRangeBoundariesStruct +// template +// KOKKOS_INLINE_FUNCTION +// Impl::TeamThreadRangeBoundariesStruct // < typename std::common_type::type // , Impl::TaskExec< Kokkos::Cuda > > -//TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread +// TeamThreadRange( const Impl::TaskExec< Kokkos::Cuda > & thread // , const iType1 & begin, const iType2 & end ) //{ // typedef typename std::common_type< iType1, iType2 >::type iType; -// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< Kokkos::Cuda > >( +// return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::TaskExec< +// Kokkos::Cuda > >( // thread, iType(begin), iType(end) ); //} // -//template -//KOKKOS_INLINE_FUNCTION -//Impl::ThreadVectorRangeBoundariesStruct > -//ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread +// template +// KOKKOS_INLINE_FUNCTION +// Impl::ThreadVectorRangeBoundariesStruct +// > ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread // , const iType & count ) //{ -// return Impl::ThreadVectorRangeBoundariesStruct >(thread,count); +// return Impl::ThreadVectorRangeBoundariesStruct >(thread,count); //} // -//template -//KOKKOS_INLINE_FUNCTION -//Impl::ThreadVectorRangeBoundariesStruct > -//ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread +// template +// KOKKOS_INLINE_FUNCTION +// Impl::ThreadVectorRangeBoundariesStruct +// > ThreadVectorRange( const Impl::TaskExec< Kokkos::Cuda > & thread // , const iType & arg_begin // , const iType & arg_end ) //{ -// return Impl::ThreadVectorRangeBoundariesStruct >(thread,arg_begin,arg_end); +// return Impl::ThreadVectorRangeBoundariesStruct >(thread,arg_begin,arg_end); //} // KOKKOS_INLINE_FUNCTION @@ -829,78 +795,70 @@ namespace Kokkos { // return Impl::VectorSingleStruct >(thread); // } -/** \brief Inter-thread parallel_for. Executes lambda(iType i) for each i=0..N-1. +/** \brief Inter-thread parallel_for. Executes lambda(iType i) for each + * i=0..N-1. * * The range i=0..N-1 is mapped to all threads of the the calling thread team. * This functionality requires C++11 support. -*/ -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries - , const Lambda& lambda - ) -{ - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { + */ +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda) { + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { lambda(i); } } -template< typename iType, class Lambda, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_for - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda) { - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda) { + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { lambda(i); } } // reduce across corresponding lanes between team members within warp // assume stride*team_size == warp_size -template< typename ValueType, class JoinType > -KOKKOS_INLINE_FUNCTION -void strided_shfl_warp_reduction - (const JoinType& join, - ValueType& val, - int team_size, - int stride) -{ - for (int lane_delta=(team_size*stride)>>1; lane_delta>=stride; lane_delta>>=1) { - join(val, Kokkos::shfl_down(val, lane_delta, team_size*stride)); +template +KOKKOS_INLINE_FUNCTION void strided_shfl_warp_reduction(const JoinType& join, + ValueType& val, + int team_size, + int stride) { + for (int lane_delta = (team_size * stride) >> 1; lane_delta >= stride; + lane_delta >>= 1) { + join(val, Kokkos::shfl_down(val, lane_delta, team_size * stride)); } } // multiple within-warp non-strided reductions -template< typename ValueType, class JoinType > -KOKKOS_INLINE_FUNCTION -void multi_shfl_warp_reduction - (const JoinType& join, - ValueType& val, - int vec_length) -{ - for (int lane_delta=vec_length>>1; lane_delta; lane_delta>>=1) { +template +KOKKOS_INLINE_FUNCTION void multi_shfl_warp_reduction(const JoinType& join, + ValueType& val, + int vec_length) { + for (int lane_delta = vec_length >> 1; lane_delta; lane_delta >>= 1) { join(val, Kokkos::shfl_down(val, lane_delta, vec_length)); } } // broadcast within warp -template< class ValueType > -KOKKOS_INLINE_FUNCTION -ValueType shfl_warp_broadcast - (ValueType& val, - int src_lane, - int width) -{ - if ( 1 < width ) { +template +KOKKOS_INLINE_FUNCTION ValueType shfl_warp_broadcast(ValueType& val, + int src_lane, int width) { + if (1 < width) { return Kokkos::shfl(val, src_lane, width); - } - else { - return val ; + } else { + return val; } } -/*// all-reduce across corresponding vector lanes between team members within warp +/*// all-reduce across corresponding vector lanes between team members within +warp // assume vec_length*team_size == warp_size // blockDim.x == vec_length == stride // blockDim.y == team_size @@ -909,14 +867,13 @@ ValueType shfl_warp_broadcast template< typename iType, class Lambda, typename ValueType, class JoinType > KOKKOS_INLINE_FUNCTION void parallel_reduce - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const JoinType& join, + (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, const Lambda & lambda, const JoinType& join, ValueType& initialized_result) { ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for( iType i = loop_boundaries.start; i < loop_boundaries.end; +i+=loop_boundaries.increment) { lambda(i,result); } initialized_result = result; @@ -925,7 +882,8 @@ void parallel_reduce initialized_result, loop_boundaries.thread.team_size(), blockDim.x); - initialized_result = shfl_warp_broadcast( initialized_result, threadIdx.x, Impl::CudaTraits::WarpSize ); + initialized_result = shfl_warp_broadcast( initialized_result, +threadIdx.x, Impl::CudaTraits::WarpSize ); }*/ // all-reduce across corresponding vector lanes between team members within warp @@ -935,63 +893,55 @@ void parallel_reduce // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Lambda, typename ValueType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - ValueType& initialized_result) { - - //TODO @internal_documentation what is the point of creating this temporary? +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, ValueType& initialized_result) { + // TODO @internal_documentation what is the point of creating this temporary? ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } initialized_result = result; - if ( 1 < loop_boundaries.thread.team_size() ) { - + if (1 < loop_boundaries.thread.team_size()) { strided_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { val1 += val2; }, - initialized_result, - loop_boundaries.thread.team_size(), - blockDim.x); + [&](ValueType& val1, const ValueType& val2) { val1 += val2; }, + initialized_result, loop_boundaries.thread.team_size(), blockDim.x); - initialized_result = - shfl_warp_broadcast( - initialized_result, threadIdx.x, Impl::CudaTraits::WarpSize ); + initialized_result = shfl_warp_broadcast( + initialized_result, threadIdx.x, Impl::CudaTraits::WarpSize); } } -template< typename iType, class Lambda, typename ReducerType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const ReducerType& reducer) { - +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, const ReducerType& reducer) { typedef typename ReducerType::value_type ValueType; - //TODO @internal_documentation what is the point of creating this temporary? + // TODO @internal_documentation what is the point of creating this temporary? ValueType result = ValueType(); reducer.init(result); - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } - if ( 1 < loop_boundaries.thread.team_size() ) { + if (1 < loop_boundaries.thread.team_size()) { strided_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { reducer.join(val1,val2); }, - result, - loop_boundaries.thread.team_size(), - blockDim.x); - - reducer.reference() = - shfl_warp_broadcast( - result, threadIdx.x, Impl::CudaTraits::WarpSize ); - } - else { - reducer.reference() = result ; + [&](ValueType& val1, const ValueType& val2) { + reducer.join(val1, val2); + }, + result, loop_boundaries.thread.team_size(), blockDim.x); + + reducer.reference() = shfl_warp_broadcast( + result, threadIdx.x, Impl::CudaTraits::WarpSize); + } else { + reducer.reference() = result; } } // all-reduce within team members within warp @@ -1003,19 +953,19 @@ void parallel_reduce /*template< typename iType, class Lambda, typename ValueType, class JoinType > KOKKOS_INLINE_FUNCTION void parallel_reduce - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const JoinType& join, + (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, const Lambda & lambda, const JoinType& join, ValueType& initialized_result) { ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for( iType i = loop_boundaries.start; i < loop_boundaries.end; +i+=loop_boundaries.increment) { lambda(i,result); } initialized_result = result; - multi_shfl_warp_reduction(join, initialized_result, blockDim.x); - initialized_result = shfl_warp_broadcast( initialized_result, 0, blockDim.x ); + multi_shfl_warp_reduction(join, initialized_result, +blockDim.x); initialized_result = shfl_warp_broadcast( +initialized_result, 0, blockDim.x ); }*/ // all-reduce within team members within warp @@ -1025,60 +975,56 @@ void parallel_reduce // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Lambda, typename ValueType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - ValueType& initialized_result) { - +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, ValueType& initialized_result) { ValueType result = initialized_result; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } initialized_result = result; - if ( 1 < loop_boundaries.thread.team_size() ) { - //initialized_result = multi_shfl_warp_reduction( + if (1 < loop_boundaries.thread.team_size()) { + // initialized_result = multi_shfl_warp_reduction( multi_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { val1 += val2; }, - initialized_result, - blockDim.x); + [&](ValueType& val1, const ValueType& val2) { val1 += val2; }, + initialized_result, blockDim.x); initialized_result = - shfl_warp_broadcast( initialized_result, 0, blockDim.x ); + shfl_warp_broadcast(initialized_result, 0, blockDim.x); } } -template< typename iType, class Lambda, typename ReducerType, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_reduce - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Lambda & lambda, - const ReducerType& reducer) { - +template +KOKKOS_INLINE_FUNCTION void parallel_reduce( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Lambda& lambda, const ReducerType& reducer) { typedef typename ReducerType::value_type ValueType; ValueType result = ValueType(); reducer.init(result); - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - lambda(i,result); + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + lambda(i, result); } - if ( 1 < loop_boundaries.thread.team_size() ) { + if (1 < loop_boundaries.thread.team_size()) { multi_shfl_warp_reduction( - [&] (ValueType& val1, const ValueType& val2) { reducer.join(val1,val2); }, - result, - blockDim.x); - - reducer.reference() = - shfl_warp_broadcast( result, 0, blockDim.x ); - } - else { - reducer.reference() = result ; + [&](ValueType& val1, const ValueType& val2) { + reducer.join(val1, val2); + }, + result, blockDim.x); + + reducer.reference() = shfl_warp_broadcast(result, 0, blockDim.x); + } else { + reducer.reference() = result; } } // scan across corresponding vector lanes between team members within warp @@ -1087,61 +1033,61 @@ void parallel_reduce // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Closure, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_scan - (const Impl::TeamThreadRangeBoundariesStruct >& loop_boundaries, - const Closure & closure ) -{ +template +KOKKOS_INLINE_FUNCTION void parallel_scan( + const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Closure& closure) { // Extract value_type from closure - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Closure >::value_type ; - - if ( 1 < loop_boundaries.thread.team_size() ) { + using value_type = typename Kokkos::Impl::FunctorAnalysis< + Kokkos::Impl::FunctorPatternInterface::SCAN, void, Closure>::value_type; + if (1 < loop_boundaries.thread.team_size()) { // make sure all threads perform all loop iterations - const iType bound = loop_boundaries.end + loop_boundaries.start ; - const int lane = threadIdx.y * blockDim.x ; + const iType bound = loop_boundaries.end + loop_boundaries.start; + const int lane = threadIdx.y * blockDim.x; - value_type accum = 0 ; + value_type accum = 0; value_type val, y, local_total; - for( iType i = loop_boundaries.start; i < bound; i+=loop_boundaries.increment) { + for (iType i = loop_boundaries.start; i < bound; + i += loop_boundaries.increment) { val = 0; - if ( i < loop_boundaries.end ) closure(i,val,false); + if (i < loop_boundaries.end) closure(i, val, false); // intra-blockDim.y exclusive scan on 'val' // accum = accumulated, sum in total for this iteration // INCLUSIVE scan - for( int offset = blockDim.x ; offset < Impl::CudaTraits::WarpSize ; offset <<= 1 ) { + for (int offset = blockDim.x; offset < Impl::CudaTraits::WarpSize; + offset <<= 1) { y = Kokkos::shfl_up(val, offset, Impl::CudaTraits::WarpSize); - if(lane >= offset) { val += y; } + if (lane >= offset) { + val += y; + } } // pass accum to all threads local_total = shfl_warp_broadcast( - val, - threadIdx.x+Impl::CudaTraits::WarpSize-blockDim.x, - Impl::CudaTraits::WarpSize); + val, threadIdx.x + Impl::CudaTraits::WarpSize - blockDim.x, + Impl::CudaTraits::WarpSize); // make EXCLUSIVE scan by shifting values over one val = Kokkos::shfl_up(val, blockDim.x, Impl::CudaTraits::WarpSize); - if ( threadIdx.y == 0 ) { val = 0 ; } + if (threadIdx.y == 0) { + val = 0; + } val += accum; - if ( i < loop_boundaries.end ) closure(i,val,true); + if (i < loop_boundaries.end) closure(i, val, true); accum += local_total; } - } - else { - value_type accum = 0 ; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - closure(i,accum,true); + } else { + value_type accum = 0; + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + closure(i, accum, true); } } } @@ -1152,57 +1098,58 @@ void parallel_scan // blockDim.y == team_size // threadIdx.x == position in vec // threadIdx.y == member number -template< typename iType, class Closure, class Scheduler > -KOKKOS_INLINE_FUNCTION -void parallel_scan - (const Impl::ThreadVectorRangeBoundariesStruct >& loop_boundaries, - const Closure & closure ) -{ +template +KOKKOS_INLINE_FUNCTION void parallel_scan( + const Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::TaskExec>& loop_boundaries, + const Closure& closure) { // Extract value_type from closure - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Closure >::value_type ; - - if ( 1 < loop_boundaries.thread.team_size() ) { + using value_type = typename Kokkos::Impl::FunctorAnalysis< + Kokkos::Impl::FunctorPatternInterface::SCAN, void, Closure>::value_type; + if (1 < loop_boundaries.thread.team_size()) { // make sure all threads perform all loop iterations - const iType bound = loop_boundaries.end + loop_boundaries.start ; + const iType bound = loop_boundaries.end + loop_boundaries.start; - value_type accum = 0 ; + value_type accum = 0; value_type val, y, local_total; - for( iType i = loop_boundaries.start; i < bound; i+=loop_boundaries.increment) { + for (iType i = loop_boundaries.start; i < bound; + i += loop_boundaries.increment) { val = 0; - if ( i < loop_boundaries.end ) closure(i,val,false); + if (i < loop_boundaries.end) closure(i, val, false); // intra-blockDim.x exclusive scan on 'val' // accum = accumulated, sum in total for this iteration // INCLUSIVE scan - for( int offset = 1 ; offset < blockDim.x ; offset <<= 1 ) { + for (int offset = 1; offset < blockDim.x; offset <<= 1) { y = Kokkos::shfl_up(val, offset, blockDim.x); - if(threadIdx.x >= offset) { val += y; } + if (threadIdx.x >= offset) { + val += y; + } } // pass accum to all threads - local_total = shfl_warp_broadcast(val, blockDim.x-1, blockDim.x); + local_total = + shfl_warp_broadcast(val, blockDim.x - 1, blockDim.x); // make EXCLUSIVE scan by shifting values over one val = Kokkos::shfl_up(val, 1, blockDim.x); - if ( threadIdx.x == 0 ) { val = 0 ; } + if (threadIdx.x == 0) { + val = 0; + } val += accum; - if ( i < loop_boundaries.end ) closure(i,val,true); + if (i < loop_boundaries.end) closure(i, val, true); accum += local_total; } - } - else { - value_type accum = 0 ; - for( iType i = loop_boundaries.start; i < loop_boundaries.end; i+=loop_boundaries.increment) { - closure(i,accum,true); + } else { + value_type accum = 0; + for (iType i = loop_boundaries.start; i < loop_boundaries.end; + i += loop_boundaries.increment) { + closure(i, accum, true); } } } @@ -1211,49 +1158,53 @@ void parallel_scan namespace Kokkos { - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::VectorSingleStruct >& , const FunctorType& lambda) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct>&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(); + if (threadIdx.x == 0) lambda(); #endif - } - - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::ThreadSingleStruct >& , const FunctorType& lambda) { +} + +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct>&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) lambda(); + if (threadIdx.x == 0 && threadIdx.y == 0) lambda(); #endif - } - - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::VectorSingleStruct >& s , const FunctorType& lambda, ValueType& val) { +} + +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct>& s, + const FunctorType& lambda, ValueType& val) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(val); - if ( 1 < s.team_member.team_size() ) { - val = shfl(val,0,blockDim.x); - } -#endif + if (threadIdx.x == 0) lambda(val); + if (1 < s.team_member.team_size()) { + val = shfl(val, 0, blockDim.x); } - - template - KOKKOS_INLINE_FUNCTION - void single(const Impl::ThreadSingleStruct >& single_struct, const FunctorType& lambda, ValueType& val) { -#ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) { - lambda(val); - } - single_struct.team_member.team_broadcast(val,0); #endif +} + +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct>& + single_struct, + const FunctorType& lambda, ValueType& val) { +#ifdef __CUDA_ARCH__ + if (threadIdx.x == 0 && threadIdx.y == 0) { + lambda(val); } + single_struct.team_member.team_broadcast(val, 0); +#endif +} -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */ #endif /* #ifndef KOKKOS_IMPL_CUDA_TASK_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp index 587ad6001d..ac9ab9660c 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Team.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,7 +52,7 @@ #include /* only compile this file if CUDA is enabled for Kokkos */ -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include #include @@ -72,14 +73,15 @@ namespace Kokkos { namespace Impl { -template< typename Type > +template struct CudaJoinFunctor { - typedef Type value_type ; + typedef Type value_type; KOKKOS_INLINE_FUNCTION - static void join( volatile value_type & update , - volatile const value_type & input ) - { update += input ; } + static void join(volatile value_type& update, + volatile const value_type& input) { + update += input; + } }; /**\brief Team member_type passed to TeamPolicy or TeamTask closures. @@ -101,108 +103,105 @@ struct CudaJoinFunctor { * total available shared memory must be partitioned among teams. */ class CudaTeamMember { - -public: - typedef Kokkos::Cuda execution_space ; - typedef execution_space::scratch_memory_space scratch_memory_space ; - -private: - - mutable void * m_team_reduce ; - scratch_memory_space m_team_shared ; - int m_team_reduce_size ; - int m_league_rank ; - int m_league_size ; - -public: - + public: + typedef Kokkos::Cuda execution_space; + typedef execution_space::scratch_memory_space scratch_memory_space; + + private: + mutable void* m_team_reduce; + scratch_memory_space m_team_shared; + int m_team_reduce_size; + int m_league_rank; + int m_league_size; + + public: KOKKOS_INLINE_FUNCTION - const execution_space::scratch_memory_space & team_shmem() const - { return m_team_shared.set_team_thread_mode(0,1,0) ; } + const execution_space::scratch_memory_space& team_shmem() const { + return m_team_shared.set_team_thread_mode(0, 1, 0); + } KOKKOS_INLINE_FUNCTION - const execution_space::scratch_memory_space & - team_scratch(const int& level) const - { return m_team_shared.set_team_thread_mode(level,1,0) ; } + const execution_space::scratch_memory_space& team_scratch( + const int& level) const { + return m_team_shared.set_team_thread_mode(level, 1, 0); + } KOKKOS_INLINE_FUNCTION - const execution_space::scratch_memory_space & - thread_scratch(const int& level) const - { return m_team_shared.set_team_thread_mode(level,team_size(),team_rank()) ; } - - KOKKOS_INLINE_FUNCTION int league_rank() const { return m_league_rank ; } - KOKKOS_INLINE_FUNCTION int league_size() const { return m_league_size ; } - KOKKOS_INLINE_FUNCTION int team_rank() const - { - #ifdef __CUDA_ARCH__ - return threadIdx.y ; - #else - return 0; - #endif - } + const execution_space::scratch_memory_space& thread_scratch( + const int& level) const { + return m_team_shared.set_team_thread_mode(level, team_size(), team_rank()); + } - KOKKOS_INLINE_FUNCTION int team_size() const - { - #ifdef __CUDA_ARCH__ - return blockDim.y ; - #else - return 1; - #endif - } + KOKKOS_INLINE_FUNCTION int league_rank() const { return m_league_rank; } + KOKKOS_INLINE_FUNCTION int league_size() const { return m_league_size; } + KOKKOS_INLINE_FUNCTION int team_rank() const { +#ifdef __CUDA_ARCH__ + return threadIdx.y; +#else + return 0; +#endif + } - KOKKOS_INLINE_FUNCTION void team_barrier() const - { - #ifdef __CUDA_ARCH__ - if ( 1 == blockDim.z ) __syncthreads(); // team == block - else __threadfence_block(); // team <= warp - #endif - } + KOKKOS_INLINE_FUNCTION int team_size() const { +#ifdef __CUDA_ARCH__ + return blockDim.y; +#else + return 1; +#endif + } + + KOKKOS_INLINE_FUNCTION void team_barrier() const { +#ifdef __CUDA_ARCH__ + if (1 == blockDim.z) + __syncthreads(); // team == block + else + __threadfence_block(); // team <= warp +#endif + } //-------------------------------------------------------------------------- - template - KOKKOS_INLINE_FUNCTION - void team_broadcast( ValueType & val, const int& thread_id ) const - { - #ifdef __CUDA_ARCH__ - if ( 1 == blockDim.z ) { // team == block - __syncthreads(); - // Wait for shared data write until all threads arrive here - if ( threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id ) { - *((ValueType*) m_team_reduce) = val ; - } - __syncthreads(); // Wait for shared data read until root thread writes - val = *((ValueType*) m_team_reduce); - } - else { // team <= warp - ValueType tmp( val ); // input might not be a register variable - cuda_shfl( val, tmp, blockDim.x * thread_id, blockDim.x * blockDim.y ); + template + KOKKOS_INLINE_FUNCTION void team_broadcast(ValueType& val, + const int& thread_id) const { +#ifdef __CUDA_ARCH__ + if (1 == blockDim.z) { // team == block + __syncthreads(); + // Wait for shared data write until all threads arrive here + if (threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id) { + *((ValueType*)m_team_reduce) = val; } - #endif + __syncthreads(); // Wait for shared data read until root thread writes + val = *((ValueType*)m_team_reduce); + } else { // team <= warp + ValueType tmp(val); // input might not be a register variable + Impl::in_place_shfl(val, tmp, blockDim.x * thread_id, + blockDim.x * blockDim.y); } - - template - KOKKOS_INLINE_FUNCTION - void team_broadcast( Closure const & f, ValueType & val, const int& thread_id ) const - { - #ifdef __CUDA_ARCH__ - f( val ); - - if ( 1 == blockDim.z ) { // team == block - __syncthreads(); - // Wait for shared data write until all threads arrive here - if ( threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id ) { - *((ValueType*) m_team_reduce) = val ; - } - __syncthreads(); // Wait for shared data read until root thread writes - val = *((ValueType*) m_team_reduce); - } - else { // team <= warp - ValueType tmp( val ); // input might not be a register variable - cuda_shfl( val, tmp, blockDim.x * thread_id, blockDim.x * blockDim.y ); +#endif + } + + template + KOKKOS_INLINE_FUNCTION void team_broadcast(Closure const& f, ValueType& val, + const int& thread_id) const { +#ifdef __CUDA_ARCH__ + f(val); + + if (1 == blockDim.z) { // team == block + __syncthreads(); + // Wait for shared data write until all threads arrive here + if (threadIdx.x == 0u && threadIdx.y == (uint32_t)thread_id) { + *((ValueType*)m_team_reduce) = val; } - #endif + __syncthreads(); // Wait for shared data read until root thread writes + val = *((ValueType*)m_team_reduce); + } else { // team <= warp + ValueType tmp(val); // input might not be a register variable + Impl::in_place_shfl(val, tmp, blockDim.x * thread_id, + blockDim.x * blockDim.y); } +#endif + } //-------------------------------------------------------------------------- /**\brief Reduction across a team @@ -219,24 +218,22 @@ public: * OR * ( 1 == blockDim.z ) */ - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION - typename std::enable_if< is_reducer< ReducerType >::value >::type - team_reduce( ReducerType const & reducer ) const noexcept - { - team_reduce(reducer,reducer.reference()); - } - - template< typename ReducerType > - KOKKOS_INLINE_FUNCTION - typename std::enable_if< is_reducer< ReducerType >::value >::type - team_reduce( ReducerType const & reducer, typename ReducerType::value_type& value ) const noexcept - { - #ifdef __CUDA_ARCH__ - cuda_intra_block_reduction(reducer,value,blockDim.y); - #endif /* #ifdef __CUDA_ARCH__ */ - } + typename std::enable_if::value>::type + team_reduce(ReducerType const& reducer) const noexcept { + team_reduce(reducer, reducer.reference()); + } + template + KOKKOS_INLINE_FUNCTION + typename std::enable_if::value>::type + team_reduce(ReducerType const& reducer, + typename ReducerType::value_type& value) const noexcept { +#ifdef __CUDA_ARCH__ + cuda_intra_block_reduction(reducer, value, blockDim.y); +#endif /* #ifdef __CUDA_ARCH__ */ + } //-------------------------------------------------------------------------- /** \brief Intra-team exclusive prefix sum with team_rank() ordering @@ -248,307 +245,299 @@ public: * As such the base value for each team's scan operation is similarly * non-deterministic. */ - template< typename Type > - KOKKOS_INLINE_FUNCTION - Type team_scan( const Type & value , Type * const global_accum ) const - { - #ifdef __CUDA_ARCH__ - Type * const base_data = (Type *) m_team_reduce ; + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value, + Type* const global_accum) const { +#ifdef __CUDA_ARCH__ + Type* const base_data = (Type*)m_team_reduce; - __syncthreads(); // Don't write in to shared data until all threads have entered this function + __syncthreads(); // Don't write in to shared data until all threads have + // entered this function - if ( 0 == threadIdx.y ) { base_data[0] = 0 ; } + if (0 == threadIdx.y) { + base_data[0] = 0; + } - base_data[ threadIdx.y + 1 ] = value ; + base_data[threadIdx.y + 1] = value; - Impl::cuda_intra_block_reduce_scan,void>( Impl::CudaJoinFunctor() , base_data + 1 ); + Impl::cuda_intra_block_reduce_scan, void>( + Impl::CudaJoinFunctor(), base_data + 1); - if ( global_accum ) { - if ( blockDim.y == threadIdx.y + 1 ) { - base_data[ blockDim.y ] = atomic_fetch_add( global_accum , base_data[ blockDim.y ] ); - } - __syncthreads(); // Wait for atomic - base_data[ threadIdx.y ] += base_data[ blockDim.y ] ; + if (global_accum) { + if (blockDim.y == threadIdx.y + 1) { + base_data[blockDim.y] = + atomic_fetch_add(global_accum, base_data[blockDim.y]); } - - return base_data[ threadIdx.y ]; - #else - return Type(); - #endif + __syncthreads(); // Wait for atomic + base_data[threadIdx.y] += base_data[blockDim.y]; } + return base_data[threadIdx.y]; +#else + return Type(); +#endif + } + /** \brief Intra-team exclusive prefix sum with team_rank() ordering. * * The highest rank thread can compute the reduction total as * reduction_total = dev.team_scan( value ) + value ; */ - template< typename Type > - KOKKOS_INLINE_FUNCTION Type team_scan( const Type & value ) const { - return this->template team_scan( value , 0 ); + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value) const { + return this->template team_scan(value, 0); } //---------------------------------------- - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION static - typename std::enable_if< is_reducer< ReducerType >::value >::type - vector_reduce( ReducerType const & reducer ) { - vector_reduce(reducer,reducer.reference()); + typename std::enable_if::value>::type + vector_reduce(ReducerType const& reducer) { + vector_reduce(reducer, reducer.reference()); } - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION static - typename std::enable_if< is_reducer< ReducerType >::value >::type - vector_reduce( ReducerType const & reducer, typename ReducerType::value_type& value ) - { - - #ifdef __CUDA_ARCH__ - if(blockDim.x == 1) return; - - // Intra vector lane shuffle reduction: - typename ReducerType::value_type tmp ( value ); - typename ReducerType::value_type tmp2 = tmp; - - unsigned mask = blockDim.x==32?0xffffffff:((1<>= 1 ) ; ) { - cuda_shfl_down( tmp2 , tmp , i , blockDim.x , mask ); - if ( (int)threadIdx.x < i ) { reducer.join( tmp , tmp2 ); } + typename std::enable_if::value>::type + vector_reduce(ReducerType const& reducer, + typename ReducerType::value_type& value) { +#ifdef __CUDA_ARCH__ + if (blockDim.x == 1) return; + + // Intra vector lane shuffle reduction: + typename ReducerType::value_type tmp(value); + typename ReducerType::value_type tmp2 = tmp; + + unsigned mask = + blockDim.x == 32 + ? 0xffffffff + : ((1 << blockDim.x) - 1) + << ((threadIdx.y % (32 / blockDim.x)) * blockDim.x); + + for (int i = blockDim.x; (i >>= 1);) { + Impl::in_place_shfl_down(tmp2, tmp, i, blockDim.x, mask); + if ((int)threadIdx.x < i) { + reducer.join(tmp, tmp2); } + } - // Broadcast from root lane to all other lanes. - // Cannot use "butterfly" algorithm to avoid the broadcast - // because floating point summation is not associative - // and thus different threads could have different results. + // Broadcast from root lane to all other lanes. + // Cannot use "butterfly" algorithm to avoid the broadcast + // because floating point summation is not associative + // and thus different threads could have different results. - cuda_shfl( tmp2 , tmp , 0 , blockDim.x , mask ); - value = tmp2; - reducer.reference() = tmp2; - #endif - } + Impl::in_place_shfl(tmp2, tmp, 0, blockDim.x, mask); + value = tmp2; + reducer.reference() = tmp2; +#endif + } //-------------------------------------------------------------------------- /**\brief Global reduction across all blocks * * Return !0 if reducer contains the final value */ - template< typename ReducerType > + template KOKKOS_INLINE_FUNCTION static - typename std::enable_if< is_reducer< ReducerType >::value , int >::type - global_reduce( ReducerType const & reducer - , int * const global_scratch_flags - , void * const global_scratch_space - , void * const shmem - , int const shmem_size - ) - { - #ifdef __CUDA_ARCH__ - - typedef typename ReducerType::value_type value_type ; - typedef value_type volatile * pointer_type ; + typename std::enable_if::value, int>::type + global_reduce(ReducerType const& reducer, int* const global_scratch_flags, + void* const global_scratch_space, void* const shmem, + int const shmem_size) { +#ifdef __CUDA_ARCH__ - // Number of shared memory entries for the reduction: - const int nsh = shmem_size / sizeof(value_type); + typedef typename ReducerType::value_type value_type; + typedef value_type volatile* pointer_type; - // Number of CUDA threads in the block, rank within the block - const int nid = blockDim.x * blockDim.y * blockDim.z ; - const int tid = threadIdx.x + blockDim.x * ( - threadIdx.y + blockDim.y * threadIdx.z ); + // Number of shared memory entries for the reduction: + const int nsh = shmem_size / sizeof(value_type); - // Reduces within block using all available shared memory - // Contributes if it is the root "vector lane" + // Number of CUDA threads in the block, rank within the block + const int nid = blockDim.x * blockDim.y * blockDim.z; + const int tid = + threadIdx.x + blockDim.x * (threadIdx.y + blockDim.y * threadIdx.z); - // wn == number of warps in the block - // wx == which lane within the warp - // wy == which warp within the block + // Reduces within block using all available shared memory + // Contributes if it is the root "vector lane" - const int wn = ( nid + CudaTraits::WarpIndexMask ) >> CudaTraits::WarpIndexShift ; - const int wx = tid & CudaTraits::WarpIndexMask ; - const int wy = tid >> CudaTraits::WarpIndexShift ; + // wn == number of warps in the block + // wx == which lane within the warp + // wy == which warp within the block - //------------------------ - { // Intra warp shuffle reduction from contributing CUDA threads + const int wn = + (nid + CudaTraits::WarpIndexMask) >> CudaTraits::WarpIndexShift; + const int wx = tid & CudaTraits::WarpIndexMask; + const int wy = tid >> CudaTraits::WarpIndexShift; - value_type tmp( reducer.reference() ); + //------------------------ + { // Intra warp shuffle reduction from contributing CUDA threads - for ( int i = CudaTraits::WarpSize ; (int)blockDim.x <= ( i >>= 1 ) ; ) { + value_type tmp(reducer.reference()); - cuda_shfl_down( reducer.reference(), tmp, i, CudaTraits::WarpSize ); + for (int i = CudaTraits::WarpSize; (int)blockDim.x <= (i >>= 1);) { + Impl::in_place_shfl_down(reducer.reference(), tmp, i, + CudaTraits::WarpSize); - // Root of each vector lane reduces "thread" contribution - if ( 0 == threadIdx.x && wx < i ) { - reducer.join( & tmp , reducer.data() ); - } + // Root of each vector lane reduces "thread" contribution + if (0 == threadIdx.x && wx < i) { + reducer.join(&tmp, reducer.data()); } + } - // Reduce across warps using shared memory. - // Number of warps may not be power of two. + // Reduce across warps using shared memory. + // Number of warps may not be power of two. - __syncthreads(); // Wait before shared data write + __syncthreads(); // Wait before shared data write - // Number of shared memory entries for the reduction - // is at most one per warp - const int nentry = wn < nsh ? wn : nsh ; + // Number of shared memory entries for the reduction + // is at most one per warp + const int nentry = wn < nsh ? wn : nsh; - if ( 0 == wx && wy < nentry ) { - // Root thread of warp 'wy' has warp's value to contribute - ((value_type*) shmem)[wy] = tmp ; - } - - __syncthreads(); // Wait for write to be visible to block - - // When more warps than shared entries - // then warps must take turns joining their contribution - // to the designated shared memory entry. - for ( int i = nentry ; i < wn ; i += nentry ) { + if (0 == wx && wy < nentry) { + // Root thread of warp 'wy' has warp's value to contribute + ((value_type*)shmem)[wy] = tmp; + } - const int k = wy - i ; + __syncthreads(); // Wait for write to be visible to block - if ( 0 == wx && i <= wy && k < nentry ) { - // Root thread of warp 'wy' has warp's value to contribute - reducer.join( ((value_type*) shmem) + k , & tmp ); - } + // When more warps than shared entries + // then warps must take turns joining their contribution + // to the designated shared memory entry. + for (int i = nentry; i < wn; i += nentry) { + const int k = wy - i; - __syncthreads(); // Wait for write to be visible to block + if (0 == wx && i <= wy && k < nentry) { + // Root thread of warp 'wy' has warp's value to contribute + reducer.join(((value_type*)shmem) + k, &tmp); } - // One warp performs the inter-warp reduction: + __syncthreads(); // Wait for write to be visible to block + } - if ( 0 == wy ) { + // One warp performs the inter-warp reduction: - // Start fan-in at power of two covering nentry + if (0 == wy) { + // Start fan-in at power of two covering nentry - for ( int i = ( 1 << ( 32 - __clz(nentry-1) ) ) ; ( i >>= 1 ) ; ) { - const int k = wx + i ; - if ( wx < i && k < nentry ) { - reducer.join( ((pointer_type)shmem) + wx - , ((pointer_type)shmem) + k ); - __threadfence_block(); // Wait for write to be visible to warp - } + for (int i = (1 << (32 - __clz(nentry - 1))); (i >>= 1);) { + const int k = wx + i; + if (wx < i && k < nentry) { + reducer.join(((pointer_type)shmem) + wx, ((pointer_type)shmem) + k); + __threadfence_block(); // Wait for write to be visible to warp } } } - //------------------------ - { // Write block's value to global_scratch_memory - - int last_block = 0 ; - - if ( 0 == wx ) { - reducer.copy( ((pointer_type)global_scratch_space) - + blockIdx.x * reducer.length() - , reducer.data() ); + } + //------------------------ + { // Write block's value to global_scratch_memory - __threadfence(); // Wait until global write is visible. + int last_block = 0; - last_block = (int)gridDim.x == - 1 + Kokkos::atomic_fetch_add(global_scratch_flags,1); + if (0 == wx) { + reducer.copy(((pointer_type)global_scratch_space) + + blockIdx.x * reducer.length(), + reducer.data()); - // If last block then reset count - if ( last_block ) *global_scratch_flags = 0 ; - } + __threadfence(); // Wait until global write is visible. - last_block = __syncthreads_or( last_block ); - - if ( ! last_block ) return 0 ; + last_block = (int)gridDim.x == + 1 + Kokkos::atomic_fetch_add(global_scratch_flags, 1); + // If last block then reset count + if (last_block) *global_scratch_flags = 0; } - //------------------------ - // Last block reads global_scratch_memory into shared memory. - const int nentry = nid < gridDim.x ? - ( nid < nsh ? nid : nsh ) : - ( gridDim.x < nsh ? gridDim.x : nsh ) ; + last_block = __syncthreads_or(last_block); - // nentry = min( nid , nsh , gridDim.x ) + if (!last_block) return 0; + } + //------------------------ + // Last block reads global_scratch_memory into shared memory. - // whole block reads global memory into shared memory: + const int nentry = nid < gridDim.x ? (nid < nsh ? nid : nsh) + : (gridDim.x < nsh ? gridDim.x : nsh); - if ( tid < nentry ) { + // nentry = min( nid , nsh , gridDim.x ) - const int offset = tid * reducer.length(); + // whole block reads global memory into shared memory: - reducer.copy( ((pointer_type)shmem) + offset - , ((pointer_type)global_scratch_space) + offset ); + if (tid < nentry) { + const int offset = tid * reducer.length(); - for ( int i = nentry + tid ; i < (int)gridDim.x ; i += nentry ) { - reducer.join( ((pointer_type)shmem) + offset - , ((pointer_type)global_scratch_space) - + i * reducer.length() ); - } - } + reducer.copy(((pointer_type)shmem) + offset, + ((pointer_type)global_scratch_space) + offset); - __syncthreads(); // Wait for writes to be visible to block + for (int i = nentry + tid; i < (int)gridDim.x; i += nentry) { + reducer.join( + ((pointer_type)shmem) + offset, + ((pointer_type)global_scratch_space) + i * reducer.length()); + } + } - if ( 0 == wy ) { + __syncthreads(); // Wait for writes to be visible to block - // Iterate to reduce shared memory to single warp fan-in size + if (0 == wy) { + // Iterate to reduce shared memory to single warp fan-in size - const int nreduce = CudaTraits::WarpSize < nentry - ? CudaTraits::WarpSize : nentry ; + const int nreduce = + CudaTraits::WarpSize < nentry ? CudaTraits::WarpSize : nentry; - // nreduce = min( CudaTraits::WarpSize , nsh , gridDim.x ) + // nreduce = min( CudaTraits::WarpSize , nsh , gridDim.x ) - if ( wx < nreduce && nreduce < nentry ) { - for ( int i = nreduce + wx ; i < nentry ; i += nreduce ) { - reducer.join( ((pointer_type)shmem) + wx - , ((pointer_type)shmem) + i ); - } - __threadfence_block(); // Wait for writes to be visible to warp + if (wx < nreduce && nreduce < nentry) { + for (int i = nreduce + wx; i < nentry; i += nreduce) { + reducer.join(((pointer_type)shmem) + wx, ((pointer_type)shmem) + i); } + __threadfence_block(); // Wait for writes to be visible to warp + } - // Start fan-in at power of two covering nentry - - for ( int i = ( 1 << ( 32 - __clz(nreduce-1) ) ) ; ( i >>= 1 ) ; ) { - const int k = wx + i ; - if ( wx < i && k < nreduce ) { - reducer.join( ((pointer_type)shmem) + wx - , ((pointer_type)shmem) + k ); - __threadfence_block(); // Wait for writes to be visible to warp - } - } + // Start fan-in at power of two covering nentry - if ( 0 == wx ) { - reducer.copy( reducer.data() , (pointer_type)shmem ); - return 1 ; + for (int i = (1 << (32 - __clz(nreduce - 1))); (i >>= 1);) { + const int k = wx + i; + if (wx < i && k < nreduce) { + reducer.join(((pointer_type)shmem) + wx, ((pointer_type)shmem) + k); + __threadfence_block(); // Wait for writes to be visible to warp } } - return 0 ; - #else - return 0 ; - #endif + if (0 == wx) { + reducer.copy(reducer.data(), (pointer_type)shmem); + return 1; + } } + return 0; + +#else + return 0; +#endif + } //---------------------------------------- // Private for the driver KOKKOS_INLINE_FUNCTION - CudaTeamMember( void * shared - , const int shared_begin - , const int shared_size - , void* scratch_level_1_ptr - , const int scratch_level_1_size - , const int arg_league_rank - , const int arg_league_size ) - : m_team_reduce( shared ) - , m_team_shared( ((char *)shared) + shared_begin , shared_size, scratch_level_1_ptr, scratch_level_1_size) - , m_team_reduce_size( shared_begin ) - , m_league_rank( arg_league_rank ) - , m_league_size( arg_league_size ) - {} - -public: + CudaTeamMember(void* shared, const int shared_begin, const int shared_size, + void* scratch_level_1_ptr, const int scratch_level_1_size, + const int arg_league_rank, const int arg_league_size) + : m_team_reduce(shared), + m_team_shared(((char*)shared) + shared_begin, shared_size, + scratch_level_1_ptr, scratch_level_1_size), + m_team_reduce_size(shared_begin), + m_league_rank(arg_league_rank), + m_league_size(arg_league_size) {} + + public: // Declare to avoid unused private member warnings which are trigger // when SFINAE excludes the member function which uses these variables // Making another class a friend also surpresses these warnings - bool impl_avoid_sfinae_warning() const noexcept - { + bool impl_avoid_sfinae_warning() const noexcept { return m_team_reduce_size > 0 && m_team_reduce != nullptr; } }; -} // namspace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -556,124 +545,128 @@ public: namespace Kokkos { namespace Impl { -template -struct TeamThreadRangeBoundariesStruct { +template +struct TeamThreadRangeBoundariesStruct { typedef iType index_type; const CudaTeamMember& member; const iType start; const iType end; KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct (const CudaTeamMember& thread_, iType count) - : member(thread_) - , start( 0 ) - , end( count ) {} + TeamThreadRangeBoundariesStruct(const CudaTeamMember& thread_, iType count) + : member(thread_), start(0), end(count) {} KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct (const CudaTeamMember& thread_, iType begin_, iType end_) - : member(thread_) - , start( begin_ ) - , end( end_ ) {} + TeamThreadRangeBoundariesStruct(const CudaTeamMember& thread_, iType begin_, + iType end_) + : member(thread_), start(begin_), end(end_) {} }; -template -struct TeamVectorRangeBoundariesStruct { +template +struct TeamVectorRangeBoundariesStruct { typedef iType index_type; const CudaTeamMember& member; const iType start; const iType end; KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct (const CudaTeamMember& thread_, const iType& count) - : member(thread_) - , start( 0 ) - , end( count ) {} + TeamVectorRangeBoundariesStruct(const CudaTeamMember& thread_, + const iType& count) + : member(thread_), start(0), end(count) {} KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct (const CudaTeamMember& thread_, const iType& begin_, const iType& end_) - : member(thread_) - , start( begin_ ) - , end( end_ ) {} + TeamVectorRangeBoundariesStruct(const CudaTeamMember& thread_, + const iType& begin_, const iType& end_) + : member(thread_), start(begin_), end(end_) {} }; -template -struct ThreadVectorRangeBoundariesStruct { +template +struct ThreadVectorRangeBoundariesStruct { typedef iType index_type; const index_type start; const index_type end; KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (const CudaTeamMember, index_type count) - : start( static_cast(0) ), end( count ) {} + ThreadVectorRangeBoundariesStruct(const CudaTeamMember, index_type count) + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (index_type count) - : start( static_cast(0) ), end( count ) {} + ThreadVectorRangeBoundariesStruct(index_type count) + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (const CudaTeamMember, index_type arg_begin, index_type arg_end) - : start( arg_begin ), end( arg_end ) {} + ThreadVectorRangeBoundariesStruct(const CudaTeamMember, index_type arg_begin, + index_type arg_end) + : start(arg_begin), end(arg_end) {} KOKKOS_INLINE_FUNCTION - ThreadVectorRangeBoundariesStruct (index_type arg_begin, index_type arg_end) - : start( arg_begin ), end( arg_end ) {} + ThreadVectorRangeBoundariesStruct(index_type arg_begin, index_type arg_end) + : start(arg_begin), end(arg_end) {} }; -} // namespace Impl +} // namespace Impl -template +template KOKKOS_INLINE_FUNCTION -Impl::TeamThreadRangeBoundariesStruct< iType, Impl::CudaTeamMember > -TeamThreadRange( const Impl::CudaTeamMember & thread, iType count ) { - return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, count ); + Impl::TeamThreadRangeBoundariesStruct + TeamThreadRange(const Impl::CudaTeamMember& thread, iType count) { + return Impl::TeamThreadRangeBoundariesStruct( + thread, count); } -template< typename iType1, typename iType2 > -KOKKOS_INLINE_FUNCTION -Impl::TeamThreadRangeBoundariesStruct< typename std::common_type< iType1, iType2 >::type, - Impl::CudaTeamMember > -TeamThreadRange( const Impl::CudaTeamMember & thread, iType1 begin, iType2 end ) { - typedef typename std::common_type< iType1, iType2 >::type iType; - return Impl::TeamThreadRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, iType(begin), iType(end) ); +template +KOKKOS_INLINE_FUNCTION Impl::TeamThreadRangeBoundariesStruct< + typename std::common_type::type, Impl::CudaTeamMember> +TeamThreadRange(const Impl::CudaTeamMember& thread, iType1 begin, iType2 end) { + typedef typename std::common_type::type iType; + return Impl::TeamThreadRangeBoundariesStruct( + thread, iType(begin), iType(end)); } -template +template KOKKOS_INLINE_FUNCTION -Impl::TeamVectorRangeBoundariesStruct< iType, Impl::CudaTeamMember > -TeamVectorRange( const Impl::CudaTeamMember & thread, const iType & count ) { - return Impl::TeamVectorRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, count ); + Impl::TeamVectorRangeBoundariesStruct + TeamVectorRange(const Impl::CudaTeamMember& thread, const iType& count) { + return Impl::TeamVectorRangeBoundariesStruct( + thread, count); } -template< typename iType1, typename iType2 > -KOKKOS_INLINE_FUNCTION -Impl::TeamVectorRangeBoundariesStruct< typename std::common_type< iType1, iType2 >::type, - Impl::CudaTeamMember > -TeamVectorRange( const Impl::CudaTeamMember & thread, const iType1 & begin, const iType2 & end ) { - typedef typename std::common_type< iType1, iType2 >::type iType; - return Impl::TeamVectorRangeBoundariesStruct< iType, Impl::CudaTeamMember >( thread, iType(begin), iType(end) ); +template +KOKKOS_INLINE_FUNCTION Impl::TeamVectorRangeBoundariesStruct< + typename std::common_type::type, Impl::CudaTeamMember> +TeamVectorRange(const Impl::CudaTeamMember& thread, const iType1& begin, + const iType2& end) { + typedef typename std::common_type::type iType; + return Impl::TeamVectorRangeBoundariesStruct( + thread, iType(begin), iType(end)); } -template +template KOKKOS_INLINE_FUNCTION -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange(const Impl::CudaTeamMember& thread, iType count) { - return Impl::ThreadVectorRangeBoundariesStruct(thread,count); + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const Impl::CudaTeamMember& thread, iType count) { + return Impl::ThreadVectorRangeBoundariesStruct( + thread, count); } -template +template KOKKOS_INLINE_FUNCTION -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange(const Impl::CudaTeamMember& thread, iType arg_begin, iType arg_end) { - return Impl::ThreadVectorRangeBoundariesStruct(thread,arg_begin,arg_end); + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const Impl::CudaTeamMember& thread, iType arg_begin, + iType arg_end) { + return Impl::ThreadVectorRangeBoundariesStruct( + thread, arg_begin, arg_end); } KOKKOS_INLINE_FUNCTION -Impl::ThreadSingleStruct PerTeam(const Impl::CudaTeamMember& thread) { +Impl::ThreadSingleStruct PerTeam( + const Impl::CudaTeamMember& thread) { return Impl::ThreadSingleStruct(thread); } KOKKOS_INLINE_FUNCTION -Impl::VectorSingleStruct PerThread(const Impl::CudaTeamMember& thread) { +Impl::VectorSingleStruct PerThread( + const Impl::CudaTeamMember& thread) { return Impl::VectorSingleStruct(thread); } @@ -685,20 +678,16 @@ Impl::VectorSingleStruct PerThread(const Impl::CudaTeamMem * * The range [0..N) is mapped to all threads of the the calling thread team. */ -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::TeamThreadRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ - #ifdef __CUDA_ARCH__ - for( iType i = loop_boundaries.start + threadIdx.y - ; i < loop_boundaries.end - ; i += blockDim.y ) +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::TeamThreadRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { +#ifdef __CUDA_ARCH__ + for (iType i = loop_boundaries.start + threadIdx.y; i < loop_boundaries.end; + i += blockDim.y) closure(i); - #endif +#endif } //---------------------------------------------------------------------------- @@ -711,32 +700,26 @@ void parallel_for * calling thread team and a summation of val is * performed and put into result. */ -template< typename iType, class Closure, class ReducerType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< Kokkos::is_reducer< ReducerType >::value >::type -parallel_reduce - ( const Impl::TeamThreadRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , const ReducerType & reducer - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, const ReducerType& reducer) { #ifdef __CUDA_ARCH__ typename ReducerType::value_type value; - reducer.init( value ); + reducer.init(value); - for( iType i = loop_boundaries.start + threadIdx.y - ; i < loop_boundaries.end - ; i += blockDim.y ) { - closure(i,value); + for (iType i = loop_boundaries.start + threadIdx.y; i < loop_boundaries.end; + i += blockDim.y) { + closure(i, value); } - loop_boundaries.member.team_reduce( reducer, value ); + loop_boundaries.member.team_reduce(reducer, value); #endif } - /** \brief Inter-thread parallel_reduce assuming summation. * * Executes closure(iType i, ValueType & val) for each i=[0..N) @@ -745,98 +728,79 @@ parallel_reduce * calling thread team and a summation of val is * performed and put into result. */ -template< typename iType, class Closure, typename ValueType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< ! Kokkos::is_reducer< ValueType >::value >::type -parallel_reduce - ( const Impl::TeamThreadRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , ValueType & result - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamThreadRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, ValueType& result) { #ifdef __CUDA_ARCH__ ValueType val; Kokkos::Sum reducer(val); - reducer.init( reducer.reference() ); + reducer.init(reducer.reference()); - for( iType i = loop_boundaries.start + threadIdx.y - ; i < loop_boundaries.end - ; i += blockDim.y ) { - closure(i,val); + for (iType i = loop_boundaries.start + threadIdx.y; i < loop_boundaries.end; + i += blockDim.y) { + closure(i, val); } - loop_boundaries.member.team_reduce( reducer , val); + loop_boundaries.member.team_reduce(reducer, val); result = reducer.reference(); #endif } -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::TeamVectorRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ - #ifdef __CUDA_ARCH__ - for( iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.y*blockDim.x ) +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::TeamVectorRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { +#ifdef __CUDA_ARCH__ + for (iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x; + i < loop_boundaries.end; i += blockDim.y * blockDim.x) closure(i); - #endif +#endif } -template< typename iType, class Closure, class ReducerType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< Kokkos::is_reducer< ReducerType >::value >::type -parallel_reduce - ( const Impl::TeamVectorRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , const ReducerType & reducer - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, const ReducerType& reducer) { #ifdef __CUDA_ARCH__ typename ReducerType::value_type value; - reducer.init( value ); + reducer.init(value); - for( iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.y * blockDim.x ) { - closure(i,value); + for (iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x; + i < loop_boundaries.end; i += blockDim.y * blockDim.x) { + closure(i, value); } - loop_boundaries.member.vector_reduce( reducer, value ); - loop_boundaries.member.team_reduce( reducer, value ); + loop_boundaries.member.vector_reduce(reducer, value); + loop_boundaries.member.team_reduce(reducer, value); #endif } -template< typename iType, class Closure, typename ValueType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< ! Kokkos::is_reducer< ValueType >::value >::type -parallel_reduce - ( const Impl::TeamVectorRangeBoundariesStruct & - loop_boundaries - , const Closure & closure - , ValueType & result - ) -{ + typename std::enable_if::value>::type + parallel_reduce(const Impl::TeamVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember>& loop_boundaries, + const Closure& closure, ValueType& result) { #ifdef __CUDA_ARCH__ ValueType val; Kokkos::Sum reducer(val); - reducer.init( reducer.reference() ); + reducer.init(reducer.reference()); - for( iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.y * blockDim.x ) { - closure(i,val); + for (iType i = loop_boundaries.start + threadIdx.y * blockDim.x + threadIdx.x; + i < loop_boundaries.end; i += blockDim.y * blockDim.x) { + closure(i, val); } - loop_boundaries.member.vector_reduce( reducer ); - loop_boundaries.member.team_reduce( reducer ); + loop_boundaries.member.vector_reduce(reducer); + loop_boundaries.member.team_reduce(reducer); result = reducer.reference(); #endif } @@ -849,25 +813,24 @@ parallel_reduce * * The range [0..N) is mapped to all vector lanes of the the calling thread. */ -template -KOKKOS_INLINE_FUNCTION -void parallel_for - ( const Impl::ThreadVectorRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ +template +KOKKOS_INLINE_FUNCTION void parallel_for( + const Impl::ThreadVectorRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { #ifdef __CUDA_ARCH__ - for ( iType i = loop_boundaries.start + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.x ) { + for (iType i = loop_boundaries.start + threadIdx.x; i < loop_boundaries.end; + i += blockDim.x) { closure(i); } - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - KOKKOS_IMPL_CUDA_SYNCWARP_MASK(blockDim.x==32?0xffffffff:((1< +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< is_reducer< ReducerType >::value >::type -parallel_reduce - ( Impl::ThreadVectorRangeBoundariesStruct - const & loop_boundaries - , Closure const & closure - , ReducerType const & reducer ) -{ + typename std::enable_if::value>::type + parallel_reduce(Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember> const& loop_boundaries, + Closure const& closure, ReducerType const& reducer) { #ifdef __CUDA_ARCH__ - reducer.init( reducer.reference() ); + reducer.init(reducer.reference()); - for ( iType i = loop_boundaries.start + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.x ) { - closure(i,reducer.reference()); + for (iType i = loop_boundaries.start + threadIdx.x; i < loop_boundaries.end; + i += blockDim.x) { + closure(i, reducer.reference()); } - Impl::CudaTeamMember::vector_reduce( reducer ); + Impl::CudaTeamMember::vector_reduce(reducer); #endif } @@ -919,26 +878,21 @@ parallel_reduce * The identity value for the += operator is assumed to be the default * constructed value. */ -template< typename iType, class Closure, typename ValueType > +template KOKKOS_INLINE_FUNCTION -typename std::enable_if< ! is_reducer< ValueType >::value >::type -parallel_reduce - ( Impl::ThreadVectorRangeBoundariesStruct - const & loop_boundaries - , Closure const & closure - , ValueType & result ) -{ + typename std::enable_if::value>::type + parallel_reduce(Impl::ThreadVectorRangeBoundariesStruct< + iType, Impl::CudaTeamMember> const& loop_boundaries, + Closure const& closure, ValueType& result) { #ifdef __CUDA_ARCH__ result = ValueType(); - for ( iType i = loop_boundaries.start + threadIdx.x - ; i < loop_boundaries.end - ; i += blockDim.x ) { - closure(i,result); + for (iType i = loop_boundaries.start + threadIdx.x; i < loop_boundaries.end; + i += blockDim.x) { + closure(i, result); } - Impl::CudaTeamMember::vector_reduce( - Kokkos::Sum(result ) ); + Impl::CudaTeamMember::vector_reduce(Kokkos::Sum(result)); #endif } @@ -953,29 +907,22 @@ parallel_reduce * thread and a scan operation is performed. * The last call to closure has final == true. */ -template< typename iType, class Closure > -KOKKOS_INLINE_FUNCTION -void parallel_scan - ( const Impl::ThreadVectorRangeBoundariesStruct& - loop_boundaries - , const Closure & closure - ) -{ - +template +KOKKOS_INLINE_FUNCTION void parallel_scan( + const Impl::ThreadVectorRangeBoundariesStruct& + loop_boundaries, + const Closure& closure) { #ifdef __CUDA_ARCH__ // Extract value_type from closure - using value_type = - typename Kokkos::Impl::FunctorAnalysis - < Kokkos::Impl::FunctorPatternInterface::SCAN - , void - , Closure >::value_type ; + using value_type = typename Kokkos::Impl::FunctorAnalysis< + Kokkos::Impl::FunctorPatternInterface::SCAN, void, Closure>::value_type; // Loop through boundaries by vector-length chunks // must scan at each iteration - value_type accum = 0 ; + value_type accum = 0; // All thread "lanes" must loop the same number of times. // Determine an loop end for all thread "lanes." @@ -984,19 +931,21 @@ void parallel_scan // ( end % blockDim.x ) == ( end & ( blockDim.x - 1 ) ) // 1 <= blockDim.x <= CudaTraits::WarpSize - const int mask = blockDim.x - 1 ; - const unsigned active_mask = blockDim.x==32?0xffffffff:((1<= 4 // ... - for ( int j = 1 ; j < (int)blockDim.x ; j <<= 1 ) { - value_type tmp = 0 ; - Impl::cuda_shfl_up(tmp, sval , j , blockDim.x, active_mask ); - if ( j <= (int)threadIdx.x ) { sval += tmp ; } + for (int j = 1; j < (int)blockDim.x; j <<= 1) { + value_type tmp = 0; + Impl::in_place_shfl_up(tmp, sval, j, blockDim.x, active_mask); + if (j <= (int)threadIdx.x) { + sval += tmp; + } } // Include accumulation and remove value for exclusive scan: - val = accum + sval - val ; + val = accum + sval - val; // Provide exclusive scan value: - if ( i < loop_boundaries.end ) closure( i , val , true ); + if (i < loop_boundaries.end) closure(i, val, true); // Accumulate the last value in the inclusive scan: - Impl::cuda_shfl( sval , sval , mask , blockDim.x, active_mask ); + Impl::in_place_shfl(sval, sval, mask, blockDim.x, active_mask); - accum += sval ; + accum += sval; } #endif } -} +} // namespace Kokkos namespace Kokkos { -template -KOKKOS_INLINE_FUNCTION -void single(const Impl::VectorSingleStruct& , const FunctorType& lambda) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(); - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - KOKKOS_IMPL_CUDA_SYNCWARP_MASK(blockDim.x==32?0xffffffff:((1< -KOKKOS_INLINE_FUNCTION -void single(const Impl::ThreadSingleStruct& , const FunctorType& lambda) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct&, + const FunctorType& lambda) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) lambda(); - #ifdef KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - KOKKOS_IMPL_CUDA_SYNCWARP_MASK(blockDim.x==32?0xffffffff:((1< -KOKKOS_INLINE_FUNCTION -void single(const Impl::VectorSingleStruct& , const FunctorType& lambda, ValueType& val) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct&, + const FunctorType& lambda, ValueType& val) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0) lambda(val); - unsigned mask = blockDim.x==32?0xffffffff:((1< -KOKKOS_INLINE_FUNCTION -void single(const Impl::ThreadSingleStruct& single_struct, const FunctorType& lambda, ValueType& val) { +template +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct& single_struct, + const FunctorType& lambda, ValueType& val) { #ifdef __CUDA_ARCH__ - if(threadIdx.x == 0 && threadIdx.y == 0) { + if (threadIdx.x == 0 && threadIdx.y == 0) { lambda(val); } - single_struct.team_member.team_broadcast(val,0); + single_struct.team_member.team_broadcast(val, 0); #endif } -} // namespace Kokkos +} // namespace Kokkos #endif /* defined( __CUDACC__ ) */ #endif /* #ifndef KOKKOS_CUDA_TEAM_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp index c4140750da..a0de4eaa7f 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_UniqueToken.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,92 +53,79 @@ #include #include -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { // both global and instance Unique Tokens are implemented in the same way -template<> -class UniqueToken< Cuda, UniqueTokenScope::Global > -{ -private: - - uint32_t volatile * m_buffer ; - uint32_t m_count ; - -public: +template <> +class UniqueToken { + private: + uint32_t volatile* m_buffer; + uint32_t m_count; + public: using execution_space = Cuda; - using size_type = int32_t; + using size_type = int32_t; -#if defined( KOKKOS_ENABLE_DEPRECATED_CODE ) - explicit - UniqueToken( execution_space const& ); +#if defined(KOKKOS_ENABLE_DEPRECATED_CODE) + explicit UniqueToken(execution_space const&); KOKKOS_INLINE_FUNCTION UniqueToken() : m_buffer(0), m_count(0) {} #else - explicit - UniqueToken( execution_space const& = execution_space() ); + explicit UniqueToken(execution_space const& = execution_space()); #endif #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION - UniqueToken( const UniqueToken & rhs ) - : m_buffer(rhs.m_buffer) - , m_count(rhs.m_count) - { - } + UniqueToken(const UniqueToken& rhs) + : m_buffer(rhs.m_buffer), m_count(rhs.m_count) {} KOKKOS_INLINE_FUNCTION - UniqueToken( UniqueToken && rhs ) - : m_buffer(std::move(rhs.m_buffer)) - , m_count(std::move(rhs.m_count)) - { - } + UniqueToken(UniqueToken&& rhs) + : m_buffer(std::move(rhs.m_buffer)), m_count(std::move(rhs.m_count)) {} KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( const UniqueToken & rhs ) { + UniqueToken& operator=(const UniqueToken& rhs) { m_buffer = rhs.m_buffer; - m_count = rhs.m_count; + m_count = rhs.m_count; return *this; } KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( UniqueToken && rhs ) { + UniqueToken& operator=(UniqueToken&& rhs) { m_buffer = std::move(rhs.m_buffer); - m_count = std::move(rhs.m_count); + m_count = std::move(rhs.m_count); return *this; } #else KOKKOS_INLINE_FUNCTION - UniqueToken( const UniqueToken & ) = default; + UniqueToken(const UniqueToken&) = default; KOKKOS_INLINE_FUNCTION - UniqueToken( UniqueToken && ) = default; + UniqueToken(UniqueToken&&) = default; KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( const UniqueToken & ) = default ; + UniqueToken& operator=(const UniqueToken&) = default; KOKKOS_INLINE_FUNCTION - UniqueToken & operator=( UniqueToken && ) = default ; + UniqueToken& operator=(UniqueToken&&) = default; #endif /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type size() const noexcept { return m_count ; } + size_type size() const noexcept { return m_count; } /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type acquire() const - { - const Kokkos::pair result = - Kokkos::Impl::concurrent_bitset:: - acquire_bounded( m_buffer - , m_count - , Kokkos::Impl::clock_tic() % m_count - ); - - if ( result.first < 0 ) { - Kokkos::abort("UniqueToken failure to release tokens, no tokens available" ); + size_type acquire() const { + const Kokkos::pair result = + Kokkos::Impl::concurrent_bitset::acquire_bounded( + m_buffer, m_count, Kokkos::Impl::clock_tic() % m_count); + + if (result.first < 0) { + Kokkos::abort( + "UniqueToken failure to release tokens, no tokens available"); } return result.first; @@ -145,31 +133,26 @@ public: /// \brief release an acquired value KOKKOS_INLINE_FUNCTION - void release( size_type i ) const noexcept - { - Kokkos::Impl::concurrent_bitset::release( m_buffer, i ); + void release(size_type i) const noexcept { + Kokkos::Impl::concurrent_bitset::release(m_buffer, i); } }; -template<> -class UniqueToken< Cuda, UniqueTokenScope::Instance > - : public UniqueToken< Cuda, UniqueTokenScope::Global > -{ -public: - +template <> +class UniqueToken + : public UniqueToken { + public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - explicit - UniqueToken( execution_space const& arg ) - : UniqueToken< Cuda, UniqueTokenScope::Global >( arg ) {} + explicit UniqueToken(execution_space const& arg) + : UniqueToken(arg) {} #else - explicit - UniqueToken( execution_space const& arg = execution_space() ) - : UniqueToken< Cuda, UniqueTokenScope::Global >( arg ) {} + explicit UniqueToken(execution_space const& arg = execution_space()) + : UniqueToken(arg) {} #endif }; -}} // namespace Kokkos::Experimental - -#endif // KOKKOS_ENABLE_CUDA -#endif // KOKKOS_CUDA_UNIQUE_TOKEN_HPP +} // namespace Experimental +} // namespace Kokkos +#endif // KOKKOS_ENABLE_CUDA +#endif // KOKKOS_CUDA_UNIQUE_TOKEN_HPP diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp index fc369191bd..085262b804 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Vectorization.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,342 +49,163 @@ #include #include -namespace Kokkos { +namespace Kokkos { -// Shuffle only makes sense on >= Kepler GPUs; it doesn't work on CPUs -// or other GPUs. We provide a generic definition (which is trivial -// and doesn't do what it claims to do) because we don't actually use -// this function unless we are on a suitable GPU, with a suitable -// Scalar type. (For example, in the mat-vec, the "ThreadsPerRow" -// internal parameter depends both on the ExecutionSpace and the Scalar type, -// and it controls whether shfl_down() gets called.) namespace Impl { - template< typename Scalar > - struct shfl_union { - enum {n = sizeof(Scalar)/4}; - float fval[n]; - KOKKOS_INLINE_FUNCTION - Scalar value() { - return *(Scalar*) fval; - } - KOKKOS_INLINE_FUNCTION - void operator= (Scalar& value_) { - float* const val_ptr = (float*) &value_; - for(int i=0; i +struct in_place_shfl_op { + // CRTP boilerplate + __device__ KOKKOS_IMPL_FORCEINLINE const Derived& self() const noexcept { + return *static_cast(this); + } + + // sizeof(Scalar) == sizeof(int) case + template + // requires _assignable_from_bits + __device__ inline typename std::enable_if::type + operator()(Scalar& out, Scalar const& in, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + //------------------------------------------------ + reinterpret_cast(out) = self().do_shfl_op( + mask, reinterpret_cast(in), lane_or_delta, width); + //------------------------------------------------ + } + +// TODO: figure out why 64-bit shfl fails in Clang +#if (CUDA_VERSION >= 9000) && (!defined(KOKKOS_COMPILER_CLANG)) + // sizeof(Scalar) == sizeof(double) case + // requires _assignable_from_bits + template + __device__ inline + typename std::enable_if::type + operator()(Scalar& out, Scalar const& in, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + //------------------------------------------------ + reinterpret_cast(out) = self().do_shfl_op( + mask, *reinterpret_cast(&in), lane_or_delta, width); + //------------------------------------------------ + } +#else + // sizeof(Scalar) == sizeof(double) case + // requires _assignable_from_bits + template + __device__ inline + typename std::enable_if::type + operator()(Scalar& out, const Scalar& val, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + //------------------------------------------------ + int lo = __double2loint(*reinterpret_cast(&val)); + int hi = __double2hiint(*reinterpret_cast(&val)); + lo = self().do_shfl_op(mask, lo, lane_or_delta, width); + hi = self().do_shfl_op(mask, hi, lane_or_delta, width); + auto tmp = __hiloint2double(hi, lo); + out = reinterpret_cast(tmp); + //------------------------------------------------ + } +#endif + + // sizeof(Scalar) > sizeof(double) case + template + __device__ inline + typename std::enable_if<(sizeof(Scalar) > sizeof(double))>::type + operator()(Scalar& out, const Scalar& val, int lane_or_delta, int width, + unsigned mask = shfl_all_mask) const noexcept { + // TODO DSH shouldn't this be KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF instead of + // sizeof(int)? (Need benchmarks to decide which is faster) + using shuffle_as_t = int; + enum : int { N = sizeof(Scalar) / sizeof(shuffle_as_t) }; + + for (int i = 0; i < N; ++i) { + reinterpret_cast(&out)[i] = self().do_shfl_op( + mask, reinterpret_cast(&val)[i], lane_or_delta, + width); + } + } +}; + +struct in_place_shfl_fn : in_place_shfl_op { + template + __device__ KOKKOS_IMPL_FORCEINLINE T do_shfl_op(unsigned mask, T& val, + int lane, int width) const + noexcept { + return KOKKOS_IMPL_CUDA_SHFL_MASK(mask, val, lane, width); + } +}; +template +__device__ KOKKOS_IMPL_FORCEINLINE void in_place_shfl(Args&&... args) noexcept { + in_place_shfl_fn{}((Args &&) args...); } -#ifdef __CUDA_ARCH__ -#if (__CUDA_ARCH__ >= 300) - - KOKKOS_INLINE_FUNCTION - int shfl(const int &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - KOKKOS_INLINE_FUNCTION - float shfl(const float &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - -// TODO: figure out why 64-bit shfl fails with Clang -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - - KOKKOS_INLINE_FUNCTION - long shfl(const long &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - KOKKOS_INLINE_FUNCTION - long long shfl(const long long &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - KOKKOS_INLINE_FUNCTION - double shfl(const double &val, const int& srcLane, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL(val,srcLane,width); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type& width - ) { - Scalar tmp1 = val; - double tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL(tmp,srcLane,width); - return *reinterpret_cast(&tmp); - } - -#else // ( CUDA_VERSION < 9000 ) - - KOKKOS_INLINE_FUNCTION - double shfl(const double &val, const int& srcLane, const int& width) { - int lo = __double2loint(val); - int hi = __double2hiint(val); - lo = KOKKOS_IMPL_CUDA_SHFL(lo,srcLane,width); - hi = KOKKOS_IMPL_CUDA_SHFL(hi,srcLane,width); - return __hiloint2double(hi,lo); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) == 8) ,int>::type& width) { - int lo = __double2loint(*reinterpret_cast(&val)); - int hi = __double2hiint(*reinterpret_cast(&val)); - lo = KOKKOS_IMPL_CUDA_SHFL(lo,srcLane,width); - hi = KOKKOS_IMPL_CUDA_SHFL(hi,srcLane,width); - const double tmp = __hiloint2double(hi,lo); - return *(reinterpret_cast(&tmp)); - } - -#endif // ( CUDA_VERSION < 9000 ) - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) == 4) , int >::type& width - ) { - Scalar tmp1 = val; - float tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL(tmp,srcLane,width); - return *reinterpret_cast(&tmp); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const typename Impl::enable_if< (sizeof(Scalar) > 8) ,int>::type& width) { - Impl::shfl_union s_val; - Impl::shfl_union r_val; - s_val = val; - - for(int i = 0; i= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - - KOKKOS_INLINE_FUNCTION - long shfl_down(const long &val, const int& delta, const int& width) { - return KOKKOS_IMPL_CUDA_SHFL_DOWN(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - long long shfl_down(const long long &val, const int& delta, const int& width) { - return KOKKOS_IMPL_CUDA_SHFL_DOWN(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - double shfl_down(const double &val, const int& delta, const int& width) { - return KOKKOS_IMPL_CUDA_SHFL_DOWN(val,delta,width); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - Scalar tmp1 = val; - double tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_DOWN(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - -#else // ( CUDA_VERSION < 9000 ) - - KOKKOS_INLINE_FUNCTION - double shfl_down(const double &val, const int& delta, const int& width) { - int lo = __double2loint(val); - int hi = __double2hiint(val); - lo = KOKKOS_IMPL_CUDA_SHFL_DOWN(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_DOWN(hi,delta,width); - return __hiloint2double(hi,lo); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - int lo = __double2loint(*reinterpret_cast(&val)); - int hi = __double2hiint(*reinterpret_cast(&val)); - lo = KOKKOS_IMPL_CUDA_SHFL_DOWN(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_DOWN(hi,delta,width); - const double tmp = __hiloint2double(hi,lo); - return *(reinterpret_cast(&tmp)); - } - -#endif // ( CUDA_VERSION < 9000 ) - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 4) , int >::type & width) { - Scalar tmp1 = val; - float tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_DOWN(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) > 8) , int >::type & width) { - Impl::shfl_union s_val; - Impl::shfl_union r_val; - s_val = val; - - for(int i = 0; i= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) - - KOKKOS_INLINE_FUNCTION - long shfl_up(const long &val, const int& delta, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL_UP(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - long long shfl_up(const long long &val, const int& delta, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL_UP(val,delta,width); - } - - KOKKOS_INLINE_FUNCTION - double shfl_up(const double &val, const int& delta, const int& width ) { - return KOKKOS_IMPL_CUDA_SHFL_UP(val,delta,width); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - Scalar tmp1 = val; - double tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_UP(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - -#else // ( CUDA_VERSION < 9000 ) - - KOKKOS_INLINE_FUNCTION - double shfl_up(const double &val, const int& delta, const int& width ) { - int lo = __double2loint(val); - int hi = __double2hiint(val); - lo = KOKKOS_IMPL_CUDA_SHFL_UP(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_UP(hi,delta,width); - return __hiloint2double(hi,lo); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 8) , int >::type & width) { - int lo = __double2loint(*reinterpret_cast(&val)); - int hi = __double2hiint(*reinterpret_cast(&val)); - lo = KOKKOS_IMPL_CUDA_SHFL_UP(lo,delta,width); - hi = KOKKOS_IMPL_CUDA_SHFL_UP(hi,delta,width); - const double tmp = __hiloint2double(hi,lo); - return *(reinterpret_cast(&tmp)); - } - -#endif // ( CUDA_VERSION < 9000 ) - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) == 4) , int >::type & width) { - Scalar tmp1 = val; - float tmp = *reinterpret_cast(&tmp1); - tmp = KOKKOS_IMPL_CUDA_SHFL_UP(tmp,delta,width); - return *reinterpret_cast(&tmp); - } - - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const typename Impl::enable_if< (sizeof(Scalar) > 8) , int >::type & width) { - Impl::shfl_union s_val; - Impl::shfl_union r_val; - s_val = val; - - for(int i = 0; i - KOKKOS_INLINE_FUNCTION - Scalar shfl(const Scalar &val, const int& srcLane, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl from a device with CC<3.0."); - return val; - } +struct in_place_shfl_up_fn : in_place_shfl_op { + template + __device__ KOKKOS_IMPL_FORCEINLINE T do_shfl_op(unsigned mask, T& val, + int lane, int width) const + noexcept { + return KOKKOS_IMPL_CUDA_SHFL_UP_MASK(mask, val, lane, width); + } +}; +template +__device__ KOKKOS_IMPL_FORCEINLINE void in_place_shfl_up( + Args&&... args) noexcept { + in_place_shfl_up_fn{}((Args &&) args...); +} - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_down(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down from a device with CC<3.0."); - return val; - } +struct in_place_shfl_down_fn : in_place_shfl_op { + template + __device__ KOKKOS_IMPL_FORCEINLINE T do_shfl_op(unsigned mask, T& val, + int lane, int width) const + noexcept { + return KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(mask, val, lane, width); + } +}; +template +__device__ KOKKOS_IMPL_FORCEINLINE void in_place_shfl_down( + Args&&... args) noexcept { + in_place_shfl_down_fn{}((Args &&) args...); +} - template - KOKKOS_INLINE_FUNCTION - Scalar shfl_up(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down from a device with CC<3.0."); - return val; - } -#endif // (__CUDA_ARCH__ < 300) -#else // !defined( __CUDA_ARCH__ ) - template - inline - Scalar shfl(const Scalar &val, const int& srcLane, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl outside __CUDA_ARCH__."); - return val; - } +} // namespace Impl - template - inline - Scalar shfl_down(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down outside __CUDA_ARCH__."); - return val; - } +template +// requires default_constructible && _assignable_from_bits +__device__ inline T shfl(const T& val, const int& srcLane, const int& width, + unsigned mask = Impl::shfl_all_mask) { + T rv = {}; + Impl::in_place_shfl(rv, val, srcLane, width, mask); + return rv; +} - template - inline - Scalar shfl_up(const Scalar &val, const int& delta, const int& width) { - if(width > 1) Kokkos::abort("Error: calling shfl_down outside __CUDA_ARCH__."); - return val; - } -#endif // !defined( __CUDA_ARCH__ ) +template +// requires default_constructible && _assignable_from_bits +__device__ inline T shfl_down(const T& val, int delta, int width, + unsigned mask = Impl::shfl_all_mask) { + T rv = {}; + Impl::in_place_shfl_down(rv, val, delta, width, mask); + return rv; +} -} // end namespace Kokkos +template +// requires default_constructible && _assignable_from_bits +__device__ inline T shfl_up(const T& val, int delta, int width, + unsigned mask = Impl::shfl_all_mask) { + T rv = {}; + Impl::in_place_shfl_up(rv, val, delta, width, mask); + return rv; +} -#endif // defined( KOKKOS_ENABLE_CUDA ) -#endif // !defined( KOKKOS_CUDA_VECTORIZATION_HPP ) +} // end namespace Kokkos +#endif // defined( KOKKOS_ENABLE_CUDA ) +#endif // !defined( KOKKOS_CUDA_VECTORIZATION_HPP ) diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp index 8aa8b8f459..66231e55f9 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_Version_9_8_Compatibility.hpp @@ -1,86 +1,77 @@ -#include +#include -#if defined( __CUDA_ARCH__ ) -#if ( CUDA_VERSION < 9000 ) +#if defined(__CUDA_ARCH__) +#if (CUDA_VERSION < 9000) #define KOKKOS_IMPL_CUDA_ACTIVEMASK 0 #define KOKKOS_IMPL_CUDA_SYNCWARP __threadfence_block() -#define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) if(m)__threadfence_block() +#define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) \ + if (m) __threadfence_block() #define KOKKOS_IMPL_CUDA_BALLOT(x) __ballot(x) -#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m,x) __ballot(x) -#define KOKKOS_IMPL_CUDA_SHFL(x,y,z) __shfl(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_MASK(m,x,y,z) __shfl(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP(x,y,z) __shfl_up(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m,x,y,z) __shfl_up(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x,y,z) __shfl_down(x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m,x,y,z) __shfl_down(x,y,z) +#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m, x) __ballot(x) +#define KOKKOS_IMPL_CUDA_SHFL(x, y, z) __shfl(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_MASK(m, x, y, z) __shfl(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP(x, y, z) __shfl_up(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m, x, y, z) __shfl_up(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x, y, z) __shfl_down(x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m, x, y, z) __shfl_down(x, y, z) #else #define KOKKOS_IMPL_CUDA_ACTIVEMASK __activemask() #define KOKKOS_IMPL_CUDA_SYNCWARP __syncwarp(0xffffffff) #define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) __syncwarp(m) -#define KOKKOS_IMPL_CUDA_BALLOT(x) __ballot_sync(__activemask(),x) -#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m,x) __ballot_sync(m,x) -#define KOKKOS_IMPL_CUDA_SHFL(x,y,z) __shfl_sync(0xffffffff,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_MASK(m,x,y,z) __shfl_sync(m,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP(x,y,z) __shfl_up_sync(0xffffffff,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m,x,y,z) __shfl_up_sync(m,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x,y,z) __shfl_down_sync(0xffffffff,x,y,z) -#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m,x,y,z) __shfl_down_sync(m,x,y,z) -#endif +#define KOKKOS_IMPL_CUDA_BALLOT(x) __ballot_sync(__activemask(), x) +#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m, x) __ballot_sync(m, x) +#define KOKKOS_IMPL_CUDA_SHFL(x, y, z) __shfl_sync(0xffffffff, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_MASK(m, x, y, z) __shfl_sync(m, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP(x, y, z) __shfl_up_sync(0xffffffff, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_UP_MASK(m, x, y, z) __shfl_up_sync(m, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x, y, z) \ + __shfl_down_sync(0xffffffff, x, y, z) +#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m, x, y, z) __shfl_down_sync(m, x, y, z) +#endif #else #define KOKKOS_IMPL_CUDA_ACTIVEMASK 0 -#define KOKKOS_IMPL_CUDA_SYNCWARP +#define KOKKOS_IMPL_CUDA_SYNCWARP #define KOKKOS_IMPL_CUDA_SYNCWARP_MASK(m) (void)m #define KOKKOS_IMPL_CUDA_BALLOT(x) 0 -#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m,x) 0 -#define KOKKOS_IMPL_CUDA_SHFL(x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_MASK(m,x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_UP(x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x,y,z) 0 -#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m,x,y,z) 0 -#endif +#define KOKKOS_IMPL_CUDA_BALLOT_MASK(m, x) 0 +#define KOKKOS_IMPL_CUDA_SHFL(x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_MASK(m, x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_UP(x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_DOWN(x, y, z) 0 +#define KOKKOS_IMPL_CUDA_SHFL_DOWN_MASK(m, x, y, z) 0 +#endif -#if ( CUDA_VERSION >= 9000 ) && (!defined(KOKKOS_COMPILER_CLANG)) +#if (CUDA_VERSION >= 9000) && (!defined(KOKKOS_COMPILER_CLANG)) #define KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF sizeof(long long) #else #define KOKKOS_IMPL_CUDA_MAX_SHFL_SIZEOF sizeof(int) #endif -#if defined( __CUDA_ARCH__ ) -#if ( CUDA_VERSION < 9000 ) -#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( MSG ) { \ - const unsigned b = __ballot(1); \ - if ( b != 0xffffffff ) { \ - printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n" \ - , MSG \ - , blockIdx.x \ - , blockIdx.y \ - , blockIdx.z \ - , threadIdx.x \ - , threadIdx.y \ - , threadIdx.z \ - , b ); \ - return ; \ - } \ -} +#if defined(__CUDA_ARCH__) +#if (CUDA_VERSION < 9000) +#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN(MSG) \ + { \ + const unsigned b = __ballot(1); \ + if (b != 0xffffffff) { \ + printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n", MSG, \ + blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, \ + threadIdx.z, b); \ + return; \ + } \ + } #else -#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( MSG ) { \ - __syncwarp(); \ - const unsigned b = __activemask(); \ - if ( b != 0xffffffff ) { \ - printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n" \ - , MSG \ - , blockIdx.x \ - , blockIdx.y \ - , blockIdx.z \ - , threadIdx.x \ - , threadIdx.y \ - , threadIdx.z \ - , b ); \ - return ; \ - } \ -} -#endif +#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN(MSG) \ + { \ + __syncwarp(); \ + const unsigned b = __activemask(); \ + if (b != 0xffffffff) { \ + printf(" SYNCWARP AT %s (%d,%d,%d) (%d,%d,%d) failed %x\n", MSG, \ + blockIdx.x, blockIdx.y, blockIdx.z, threadIdx.x, threadIdx.y, \ + threadIdx.z, b); \ + return; \ + } \ + } +#endif #else -#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN( MSG ) -#endif - +#define KOKKOS_IMPL_CUDA_SYNCWARP_OR_RETURN(MSG) +#endif diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp index 2fe9d8ccf7..08fdbea387 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_View.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_EXPERIMENTAL_CUDA_VIEW_HPP #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -53,117 +54,101 @@ namespace Kokkos { namespace Impl { -// Cuda Texture fetches can be performed for 4, 8 and 16 byte objects (int,int2,int4) -// Via reinterpret_case this can be used to support all scalar types of those sizes. -// Any other scalar type falls back to either normal reads out of global memory, -// or using the __ldg intrinsic on Kepler GPUs or newer (Compute Capability >= 3.0) +// Cuda Texture fetches can be performed for 4, 8 and 16 byte objects +// (int,int2,int4) Via reinterpret_case this can be used to support all scalar +// types of those sizes. Any other scalar type falls back to either normal reads +// out of global memory, or using the __ldg intrinsic on Kepler GPUs or newer +// (Compute Capability >= 3.0) -template< typename ValueType , typename AliasType > +template struct CudaTextureFetch { - - ::cudaTextureObject_t m_obj ; - const ValueType * m_ptr ; - int m_offset ; + ::cudaTextureObject_t m_obj; + const ValueType* m_ptr; + int m_offset; // Deference operator pulls through texture object and returns by value - template< typename iType > - KOKKOS_INLINE_FUNCTION - ValueType operator[]( const iType & i ) const - { -#if defined( __CUDA_ARCH__ ) && ( 300 <= __CUDA_ARCH__ ) - AliasType v = tex1Dfetch( m_obj , i + m_offset ); - return *(reinterpret_cast (&v)); + template + KOKKOS_INLINE_FUNCTION ValueType operator[](const iType& i) const { +#if defined(__CUDA_ARCH__) && (300 <= __CUDA_ARCH__) + AliasType v = tex1Dfetch(m_obj, i + m_offset); + return *(reinterpret_cast(&v)); #else - return m_ptr[ i ]; + return m_ptr[i]; #endif - } + } // Pointer to referenced memory KOKKOS_INLINE_FUNCTION - operator const ValueType * () const { return m_ptr ; } - + operator const ValueType*() const { return m_ptr; } KOKKOS_INLINE_FUNCTION - CudaTextureFetch() : m_obj() , m_ptr() , m_offset() {} + CudaTextureFetch() : m_obj(), m_ptr(), m_offset() {} KOKKOS_INLINE_FUNCTION ~CudaTextureFetch() {} KOKKOS_INLINE_FUNCTION - CudaTextureFetch( const CudaTextureFetch & rhs ) - : m_obj( rhs.m_obj ) - , m_ptr( rhs.m_ptr ) - , m_offset( rhs.m_offset ) - {} + CudaTextureFetch(const CudaTextureFetch& rhs) + : m_obj(rhs.m_obj), m_ptr(rhs.m_ptr), m_offset(rhs.m_offset) {} KOKKOS_INLINE_FUNCTION - CudaTextureFetch( CudaTextureFetch && rhs ) - : m_obj( rhs.m_obj ) - , m_ptr( rhs.m_ptr ) - , m_offset( rhs.m_offset ) - {} + CudaTextureFetch(CudaTextureFetch&& rhs) + : m_obj(rhs.m_obj), m_ptr(rhs.m_ptr), m_offset(rhs.m_offset) {} KOKKOS_INLINE_FUNCTION - CudaTextureFetch & operator = ( const CudaTextureFetch & rhs ) - { - m_obj = rhs.m_obj ; - m_ptr = rhs.m_ptr ; - m_offset = rhs.m_offset ; - return *this ; - } + CudaTextureFetch& operator=(const CudaTextureFetch& rhs) { + m_obj = rhs.m_obj; + m_ptr = rhs.m_ptr; + m_offset = rhs.m_offset; + return *this; + } KOKKOS_INLINE_FUNCTION - CudaTextureFetch & operator = ( CudaTextureFetch && rhs ) - { - m_obj = rhs.m_obj ; - m_ptr = rhs.m_ptr ; - m_offset = rhs.m_offset ; - return *this ; - } + CudaTextureFetch& operator=(CudaTextureFetch&& rhs) { + m_obj = rhs.m_obj; + m_ptr = rhs.m_ptr; + m_offset = rhs.m_offset; + return *this; + } // Texture object spans the entire allocation. // This handle may view a subset of the allocation, so an offset is required. - template< class CudaMemorySpace > - inline explicit - CudaTextureFetch( const ValueType * const arg_ptr - , Kokkos::Impl::SharedAllocationRecord< CudaMemorySpace , void > * record - ) - : m_obj( record->template attach_texture_object< AliasType >() ) - , m_ptr( arg_ptr ) - , m_offset( record->attach_texture_object_offset( reinterpret_cast( arg_ptr ) ) ) - {} + template + inline explicit CudaTextureFetch( + const ValueType* const arg_ptr, + Kokkos::Impl::SharedAllocationRecord* record) + : m_obj(record->template attach_texture_object()), + m_ptr(arg_ptr), + m_offset(record->attach_texture_object_offset( + reinterpret_cast(arg_ptr))) {} // Texture object spans the entire allocation. // This handle may view a subset of the allocation, so an offset is required. KOKKOS_INLINE_FUNCTION - CudaTextureFetch( const CudaTextureFetch & rhs , size_t offset ) - : m_obj( rhs.m_obj ) - , m_ptr( rhs.m_ptr + offset) - , m_offset( offset + rhs.m_offset ) - {} + CudaTextureFetch(const CudaTextureFetch& rhs, size_t offset) + : m_obj(rhs.m_obj), + m_ptr(rhs.m_ptr + offset), + m_offset(offset + rhs.m_offset) {} }; -#if defined( KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ) +#if defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) -template< typename ValueType , typename AliasType > +template struct CudaLDGFetch { + const ValueType* m_ptr; - const ValueType * m_ptr ; - - template< typename iType > - KOKKOS_INLINE_FUNCTION - ValueType operator[]( const iType & i ) const - { - #ifdef __CUDA_ARCH__ - AliasType v = __ldg(reinterpret_cast(&m_ptr[i])); - return *(reinterpret_cast (&v)); - #else - return m_ptr[i]; - #endif - } + template + KOKKOS_INLINE_FUNCTION ValueType operator[](const iType& i) const { +#ifdef __CUDA_ARCH__ + AliasType v = __ldg(reinterpret_cast(&m_ptr[i])); + return *(reinterpret_cast(&v)); +#else + return m_ptr[i]; +#endif + } KOKKOS_INLINE_FUNCTION - operator const ValueType * () const { return m_ptr ; } + operator const ValueType*() const { return m_ptr; } KOKKOS_INLINE_FUNCTION CudaLDGFetch() : m_ptr() {} @@ -172,48 +157,38 @@ struct CudaLDGFetch { ~CudaLDGFetch() {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch( const CudaLDGFetch & rhs ) - : m_ptr( rhs.m_ptr ) - {} + CudaLDGFetch(const CudaLDGFetch& rhs) : m_ptr(rhs.m_ptr) {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch( CudaLDGFetch && rhs ) - : m_ptr( rhs.m_ptr ) - {} + CudaLDGFetch(CudaLDGFetch&& rhs) : m_ptr(rhs.m_ptr) {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch & operator = ( const CudaLDGFetch & rhs ) - { - m_ptr = rhs.m_ptr ; - return *this ; - } + CudaLDGFetch& operator=(const CudaLDGFetch& rhs) { + m_ptr = rhs.m_ptr; + return *this; + } KOKKOS_INLINE_FUNCTION - CudaLDGFetch & operator = ( CudaLDGFetch && rhs ) - { - m_ptr = rhs.m_ptr ; - return *this ; - } + CudaLDGFetch& operator=(CudaLDGFetch&& rhs) { + m_ptr = rhs.m_ptr; + return *this; + } - template< class CudaMemorySpace > - inline explicit - CudaLDGFetch( const ValueType * const arg_ptr - , Kokkos::Impl::SharedAllocationRecord* - ) - : m_ptr( arg_ptr ) - {} + template + inline explicit CudaLDGFetch( + const ValueType* const arg_ptr, + Kokkos::Impl::SharedAllocationRecord*) + : m_ptr(arg_ptr) {} KOKKOS_INLINE_FUNCTION - CudaLDGFetch( CudaLDGFetch const rhs ,size_t offset) - : m_ptr( rhs.m_ptr + offset ) - {} - + CudaLDGFetch(CudaLDGFetch const rhs, size_t offset) + : m_ptr(rhs.m_ptr + offset) {} }; #endif -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -221,98 +196,95 @@ struct CudaLDGFetch { namespace Kokkos { namespace Impl { -/** \brief Replace Default ViewDataHandle with Cuda texture fetch specialization - * if 'const' value type, CudaSpace and random access. +/** \brief Replace Default ViewDataHandle with Cuda texture fetch + * specialization if 'const' value type, CudaSpace and random access. */ -template< class Traits > -class ViewDataHandle< Traits , - typename std::enable_if<( - // Is Cuda memory space - ( std::is_same< typename Traits::memory_space,Kokkos::CudaSpace>::value || - std::is_same< typename Traits::memory_space,Kokkos::CudaUVMSpace>::value ) - && - // Is a trivial const value of 4, 8, or 16 bytes - std::is_trivial::value - && - std::is_same::value - && - ( sizeof(typename Traits::const_value_type) == 4 || - sizeof(typename Traits::const_value_type) == 8 || - sizeof(typename Traits::const_value_type) == 16 ) - && - // Random access trait - ( Traits::memory_traits::is_random_access != 0 ) - )>::type > -{ -public: - - using track_type = Kokkos::Impl::SharedAllocationTracker ; - - using value_type = typename Traits::const_value_type ; - using return_type = typename Traits::const_value_type ; // NOT a reference - - using alias_type = typename std::conditional< ( sizeof(value_type) == 4 ) , int , - typename std::conditional< ( sizeof(value_type) == 8 ) , ::int2 , - typename std::conditional< ( sizeof(value_type) == 16 ) , ::int4 , void - >::type - >::type - >::type ; - -#if defined( KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ) - using handle_type = Kokkos::Impl::CudaLDGFetch< value_type , alias_type > ; +template +class ViewDataHandle< + Traits, typename std::enable_if<( + // Is Cuda memory space + (std::is_same::value || + std::is_same::value) && + // Is a trivial const value of 4, 8, or 16 bytes + std::is_trivial::value && + std::is_same::value && + (sizeof(typename Traits::const_value_type) == 4 || + sizeof(typename Traits::const_value_type) == 8 || + sizeof(typename Traits::const_value_type) == 16) && + // Random access trait + (Traits::memory_traits::is_random_access != 0))>::type> { + public: + using track_type = Kokkos::Impl::SharedAllocationTracker; + + using value_type = typename Traits::const_value_type; + using return_type = typename Traits::const_value_type; // NOT a reference + + using alias_type = typename std::conditional< + (sizeof(value_type) == 4), int, + typename std::conditional< + (sizeof(value_type) == 8), ::int2, + typename std::conditional<(sizeof(value_type) == 16), ::int4, + void>::type>::type>::type; + +#if defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) + using handle_type = Kokkos::Impl::CudaLDGFetch; #else - using handle_type = Kokkos::Impl::CudaTextureFetch< value_type , alias_type > ; + using handle_type = Kokkos::Impl::CudaTextureFetch; #endif KOKKOS_INLINE_FUNCTION - static handle_type const & assign( handle_type const & arg_handle , track_type const & /* arg_tracker */ ) - { - return arg_handle ; - } + static handle_type const& assign(handle_type const& arg_handle, + track_type const& /* arg_tracker */) { + return arg_handle; + } KOKKOS_INLINE_FUNCTION - static handle_type const assign( handle_type const & arg_handle , size_t offset ) - { - return handle_type(arg_handle,offset) ; - } + static handle_type const assign(handle_type const& arg_handle, + size_t offset) { + return handle_type(arg_handle, offset); + } KOKKOS_INLINE_FUNCTION - static handle_type assign( value_type * arg_data_ptr, track_type const & arg_tracker ) - { - if(arg_data_ptr == NULL) return handle_type(); - -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - // Assignment of texture = non-texture requires creation of a texture object - // which can only occur on the host. In addition, 'get_record' is only valid - // if called in a host execution space + static handle_type assign(value_type* arg_data_ptr, + track_type const& arg_tracker) { + if (arg_data_ptr == NULL) return handle_type(); +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) + // Assignment of texture = non-texture requires creation of a texture object + // which can only occur on the host. In addition, 'get_record' is only + // valid if called in a host execution space - typedef typename Traits::memory_space memory_space ; - typedef typename Impl::SharedAllocationRecord record ; + typedef typename Traits::memory_space memory_space; + typedef typename Impl::SharedAllocationRecord record; - record * const r = arg_tracker.template get_record< memory_space >(); + record* const r = arg_tracker.template get_record(); -#if ! defined( KOKKOS_ENABLE_CUDA_LDG_INTRINSIC ) - if ( 0 == r ) { - Kokkos::abort("Cuda const random access View using Cuda texture memory requires Kokkos to allocate the View's memory"); - } +#if !defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) + if (0 == r) { + Kokkos::abort( + "Cuda const random access View using Cuda texture memory requires " + "Kokkos to allocate the View's memory"); + } #endif - return handle_type( arg_data_ptr , r ); + return handle_type(arg_data_ptr, r); #else - Kokkos::Impl::cuda_abort("Cannot create Cuda texture object from within a Cuda kernel"); - return handle_type(); + Kokkos::Impl::cuda_abort( + "Cannot create Cuda texture object from within a Cuda kernel"); + return handle_type(); #endif - } + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_VIEW_HPP */ - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp index 33615f3f9f..2fbfb67277 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIAvail.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Cuda -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp index befff1a865..18e56aa32d 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_ViewCopyETIDecl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Cuda -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp index 9c0ac470c8..0753e383a1 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_WorkGraphPolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,74 +48,64 @@ namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType - , Kokkos::WorkGraphPolicy< Traits ... > - , Kokkos::Cuda - > -{ -public: +template +class ParallelFor, + Kokkos::Cuda> { + public: + typedef Kokkos::WorkGraphPolicy Policy; + typedef ParallelFor Self; - typedef Kokkos::WorkGraphPolicy< Traits ... > Policy ; - typedef ParallelFor Self ; + private: + Policy m_policy; + FunctorType m_functor; -private: - - Policy m_policy ; - FunctorType m_functor ; - - template< class TagType > + template __device__ inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec_one( const std::int32_t w ) const noexcept - { m_functor( w ); } - - template< class TagType > - __device__ inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec_one( const std::int32_t w ) const noexcept - { const TagType t{} ; m_functor( t , w ); } - -public: + typename std::enable_if::value>::type + exec_one(const std::int32_t w) const noexcept { + m_functor(w); + } + template __device__ inline - void operator()() const noexcept - { - if ( 0 == ( threadIdx.y % 16 ) ) { - - // Spin until COMPLETED_TOKEN. - // END_TOKEN indicates no work is currently available. + typename std::enable_if::value>::type + exec_one(const std::int32_t w) const noexcept { + const TagType t{}; + m_functor(t, w); + } - for ( std::int32_t w = Policy::END_TOKEN ; - Policy::COMPLETED_TOKEN != ( w = m_policy.pop_work() ) ; ) { - if ( Policy::END_TOKEN != w ) { - exec_one< typename Policy::work_tag >( w ); - m_policy.completed_work(w); - } + public: + __device__ inline void operator()() const noexcept { + if (0 == (threadIdx.y % 16)) { + // Spin until COMPLETED_TOKEN. + // END_TOKEN indicates no work is currently available. + + for (std::int32_t w = Policy::END_TOKEN; + Policy::COMPLETED_TOKEN != (w = m_policy.pop_work());) { + if (Policy::END_TOKEN != w) { + exec_one(w); + m_policy.completed_work(w); } } } + } - inline - void execute() - { - const int warps_per_block = 4 ; - const dim3 grid( Kokkos::Impl::cuda_internal_multiprocessor_count() , 1 , 1 ); - const dim3 block( 1 , Kokkos::Impl::CudaTraits::WarpSize , warps_per_block ); - const int shared = 0 ; + inline void execute() { + const int warps_per_block = 4; + const dim3 grid(Kokkos::Impl::cuda_internal_multiprocessor_count(), 1, 1); + const dim3 block(1, Kokkos::Impl::CudaTraits::WarpSize, warps_per_block); + const int shared = 0; - Kokkos::Impl::CudaParallelLaunch(*this, grid, block, shared, Cuda().impl_internal_space_instance() , false ); + Kokkos::Impl::CudaParallelLaunch( + *this, grid, block, shared, Cuda().impl_internal_space_instance(), + false); } - inline - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy ) - : m_policy( arg_policy ) - , m_functor( arg_functor ) - {} + inline ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_policy(arg_policy), m_functor(arg_functor) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif /* #define KOKKOS_CUDA_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp index 9f5415b511..698695dbdb 100644 --- a/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp +++ b/lib/kokkos/core/src/Cuda/Kokkos_Cuda_abort.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) #include @@ -55,35 +56,26 @@ extern "C" { /* Cuda runtime function, declared in * Requires capability 2.x or better. */ -extern __device__ void __assertfail( - const void *message, - const void *file, - unsigned int line, - const void *function, - size_t charsize); +extern __device__ void __assertfail(const void *message, const void *file, + unsigned int line, const void *function, + size_t charsize); } namespace Kokkos { namespace Impl { -__device__ inline -void cuda_abort( const char * const message ) -{ +__device__ inline void cuda_abort(const char *const message) { #ifndef __APPLE__ - const char empty[] = "" ; + const char empty[] = ""; - __assertfail( (const void *) message , - (const void *) empty , - (unsigned int) 0 , - (const void *) empty , - sizeof(char) ); + __assertfail((const void *)message, (const void *)empty, (unsigned int)0, + (const void *)empty, sizeof(char)); #endif } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #else void KOKKOS_CORE_SRC_CUDA_ABORT_PREVENT_LINK_ERROR() {} #endif /* #if defined(__CUDACC__) && defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_ABORT_HPP */ - diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp b/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp index da9783467c..0c4cca70f8 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -41,7 +42,6 @@ //@HEADER */ - #include #ifdef KOKKOS_ENABLE_HPX @@ -80,8 +80,8 @@ void HPX::impl_initialize(int thread_count) { "--hpx:attach-debugger=exception", #endif }; - int argc_hpx = 1; - char name[] = "kokkos_hpx"; + int argc_hpx = 1; + char name[] = "kokkos_hpx"; char *argv_hpx[] = {name, nullptr}; hpx::start(nullptr, argc_hpx, argv_hpx, config); @@ -107,8 +107,8 @@ void HPX::impl_initialize() { "--hpx:attach-debugger=exception", #endif }; - int argc_hpx = 1; - char name[] = "kokkos_hpx"; + int argc_hpx = 1; + char name[] = "kokkos_hpx"; char *argv_hpx[] = {name, nullptr}; hpx::start(nullptr, argc_hpx, argv_hpx, config); @@ -138,15 +138,16 @@ void HPX::impl_finalize() { hpx::apply([]() { hpx::finalize(); }); hpx::stop(); } else { - Kokkos::abort("Kokkos::Experimental::HPX::impl_finalize: Kokkos started " - "HPX but something else already stopped HPX\n"); + Kokkos::abort( + "Kokkos::Experimental::HPX::impl_finalize: Kokkos started " + "HPX but something else already stopped HPX\n"); } } } -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos #else void KOKKOS_CORE_SRC_IMPL_HPX_PREVENT_LINK_ERROR() {} -#endif //#ifdef KOKKOS_ENABLE_HPX +#endif //#ifdef KOKKOS_ENABLE_HPX diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp new file mode 100644 index 0000000000..b364b4a6eb --- /dev/null +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_ChunkedRoundRobinExecutor.hpp @@ -0,0 +1,208 @@ +/* +//@HEADER +// ************************************************************************ +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ + +#ifndef KOKKOS_HPX_CHUNKEDROUNDROBINEXECUTOR_HPP +#define KOKKOS_HPX_CHUNKEDROUNDROBINEXECUTOR_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +namespace Kokkos { +namespace Impl { + +/////////////////////////////////////////////////////////////////////////// +/// A \a ChunkedRoundRobinExecutor creates groups of parallel execution +/// agents which execute in threads implicitly created by the executor. This +/// executor uses the scheduling hint to spawn threads with the first grouped on +/// the first core, the second group getting the next consecutive threads, etc. +/// For example, if 10 tasks are spawned (num_tasks is set to 10) and num_cores +/// is set to 2 the executor will schedule the tasks in the following order: +/// +/// worker thread | 1 | 2 +/// --------------+---+--- +/// tasks | 1 | 6 +/// | 2 | 7 +/// | 3 | 8 +/// | 4 | 9 +/// | 5 | 10 +/// +/// rather than the typical round robin: +/// +/// worker thread | 1 | 2 +/// --------------+---+--- +/// tasks | 1 | 2 +/// | 3 | 4 +/// | 5 | 6 +/// | 7 | 8 +/// | 9 | 10 +struct ChunkedRoundRobinExecutor { + using execution_category = hpx::parallel::execution::parallel_execution_tag; + + HPX_CONSTEXPR explicit ChunkedRoundRobinExecutor( + std::size_t num_tasks = std::size_t(-1), std::size_t core_offset = 0, + std::size_t num_cores = hpx::get_os_thread_count()) + : num_tasks_(num_tasks), + core_offset_(core_offset), + num_cores_(num_cores), + num_tasks_per_core_(double(num_tasks_) / num_cores_), + num_tasks_spawned_(0) {} + + bool operator==(ChunkedRoundRobinExecutor const &rhs) const noexcept { + return num_cores_ == rhs.num_cores_ && num_tasks_ == rhs.num_tasks_; + } + + bool operator!=(ChunkedRoundRobinExecutor const &rhs) const noexcept { + return !(*this == rhs); + } + + ChunkedRoundRobinExecutor const &context() const noexcept { return *this; } + + template + hpx::future< + typename hpx::util::detail::invoke_deferred_result::type> + async_execute(F &&f, Ts &&... ts) const { + return hpx::detail::async_launch_policy_dispatch::call( + hpx::launch::async_policy{}, std::forward(f), + std::forward(ts)...); + } + + template + void post(F &&f, Ts &&... ts) const { + hpx::util::thread_description const desc( + f, "Kokkos::Impl::ChunkedRoundRobinExecutor::async_execute"); + hpx::threads::thread_schedule_hint const hint( + hpx::threads::thread_schedule_hint_mode_thread, + core_offset_ + std::floor(double(num_tasks_spawned_ % num_tasks_) / + num_tasks_per_core_)); + + hpx::threads::register_thread_nullary( + hpx::util::deferred_call(std::forward(f), std::forward(ts)...), + desc, hpx::threads::pending, false, + hpx::threads::thread_priority_normal, hint, + hpx::threads::thread_stacksize_default); + + ++num_tasks_spawned_; + } + + template + std::vector::type>> + bulk_async_execute(F &&f, Shape const &shape, Ts &&... ts) { + hpx::util::thread_description desc( + f, "Kokkos::Impl::ChunkedRoundRobinExecutor::bulk_sync_execute"); + + hpx::lcos::local::latch l(hpx::util::size(shape)); + // Keep a separate counter for bulk launch + std::size_t num_tasks_spawned = 0; + + for (auto const &s : shape) { + hpx::threads::thread_schedule_hint const hint( + hpx::threads::thread_schedule_hint_mode_thread, + core_offset_ + std::floor(double(num_tasks_spawned % num_tasks_) / + num_tasks_per_core_)); + + hpx::threads::register_thread_nullary( + [&, s]() { + hpx::util::invoke(f, s, ts...); + l.count_down(1); + }, + desc, hpx::threads::pending, false, + hpx::threads::thread_priority_normal, hint, + hpx::threads::thread_stacksize_default); + + ++num_tasks_spawned; + } + + // NOTE: We block here to avoid extra synchronization. Since this executor + // is only used in the HPX backend we get away with this. + l.wait(); + + return {}; + } + + private: + std::size_t num_tasks_; + std::size_t core_offset_; + std::size_t num_cores_; + double num_tasks_per_core_; + mutable std::size_t num_tasks_spawned_; +}; + +} // namespace Impl +} // namespace Kokkos + +namespace hpx { +namespace parallel { +namespace execution { + +template <> +struct is_one_way_executor + : std::true_type {}; + +template <> +struct is_two_way_executor + : std::true_type {}; + +template <> +struct is_bulk_two_way_executor + : std::true_type {}; + +} // namespace execution +} // namespace parallel +} // namespace hpx + +#endif diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp index df7c403685..8d42589bdf 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.cpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,9 +58,9 @@ namespace Impl { template class TaskQueue; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #else void KOKKOS_CORE_SRC_IMPL_HPX_TASK_PREVENT_LINK_ERROR() {} -#endif // #if defined( KOKKOS_ENABLE_HPX ) && defined( KOKKOS_ENABLE_TASKDAG ) +#endif // #if defined( KOKKOS_ENABLE_HPX ) && defined( KOKKOS_ENABLE_TASKDAG ) diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp index c3a14efee6..803d955914 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_Task.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,10 +50,11 @@ #include +#include #include #include -#include +#include #include @@ -65,7 +67,7 @@ namespace Impl { template class TaskQueueSpecialization< SimpleTaskScheduler> { -public: + public: using execution_space = Kokkos::Experimental::HPX; using scheduler_type = SimpleTaskScheduler; @@ -85,7 +87,7 @@ public: // Must provide task queue execution function void execute_task() const { using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; using task_base_type = typename scheduler_type::task_base_type; const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); @@ -95,25 +97,28 @@ public: auto &queue = scheduler->queue(); - counting_semaphore sem(0); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); for (int thread = 0; thread < num_worker_threads; ++thread) { - apply([this, &sem, &queue, &buffer, num_worker_threads, thread]() { + apply(exec, [this, &num_tasks_remaining, &queue, &buffer, + num_worker_threads]() { // NOTE: This implementation has been simplified based on the // assumption that team_size = 1. The HPX backend currently only // supports a team size of 1. std::size_t t = Kokkos::Experimental::HPX::impl_hardware_thread_id(); buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()); - HPXTeamMember member(TeamPolicyInternal( - Kokkos::Experimental::HPX(), num_worker_threads, 1), - 0, t, buffer.get(t), 512); + HPXTeamMember member( + TeamPolicyInternal( + Kokkos::Experimental::HPX(), num_worker_threads, 1), + 0, t, buffer.get(t), 512); member_type single_exec(*scheduler, member); member_type &team_exec = single_exec; auto &team_scheduler = team_exec.scheduler(); - auto current_task = OptionalRef(nullptr); + auto current_task = OptionalRef(nullptr); while (!queue.is_done()) { current_task = @@ -128,11 +133,11 @@ public: } } - sem.signal(1); + num_tasks_remaining.count_down(1); }); } - sem.wait(num_worker_threads); + num_tasks_remaining.wait(); } static uint32_t get_max_team_count(execution_space const &espace) { @@ -142,11 +147,11 @@ public: template static void get_function_pointer(typename TaskType::function_type &ptr, typename TaskType::destroy_type &dtor) { - ptr = TaskType::apply; + ptr = TaskType::apply; dtor = TaskType::destroy; } -private: + private: const scheduler_type *scheduler; }; @@ -155,21 +160,21 @@ class TaskQueueSpecializationConstrained< Scheduler, typename std::enable_if< std::is_same::value>::type> { -public: + public: using execution_space = Kokkos::Experimental::HPX; - using scheduler_type = Scheduler; + using scheduler_type = Scheduler; using member_type = TaskTeamMemberAdapter; using memory_space = Kokkos::HostSpace; - static void - iff_single_thread_recursive_execute(scheduler_type const &scheduler) { + static void iff_single_thread_recursive_execute( + scheduler_type const &scheduler) { using task_base_type = typename scheduler_type::task_base; - using queue_type = typename scheduler_type::queue_type; + using queue_type = typename scheduler_type::queue_type; if (1 == Kokkos::Experimental::HPX::concurrency()) { task_base_type *const end = (task_base_type *)task_base_type::EndTag; - task_base_type *task = end; + task_base_type *task = end; HPXTeamMember member(TeamPolicyInternal( Kokkos::Experimental::HPX(), 1, 1), @@ -187,8 +192,7 @@ public: } } - if (end == task) - break; + if (end == task) break; (*task->m_apply)(task, &single_exec); @@ -210,11 +214,11 @@ public: // Must provide task queue execution function void execute_task() const { using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; using task_base_type = typename scheduler_type::task_base; - using queue_type = typename scheduler_type::queue_type; + using queue_type = typename scheduler_type::queue_type; - const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); + const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); static task_base_type *const end = (task_base_type *)task_base_type::EndTag; constexpr task_base_type *no_more_tasks_sentinel = nullptr; @@ -224,10 +228,11 @@ public: auto &queue = scheduler->queue(); queue.initialize_team_queues(num_worker_threads); - counting_semaphore sem(0); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); for (int thread = 0; thread < num_worker_threads; ++thread) { - apply([this, &sem, &buffer, num_worker_threads, thread]() { + apply(exec, [this, &num_tasks_remaining, &buffer, num_worker_threads]() { // NOTE: This implementation has been simplified based on the assumption // that team_size = 1. The HPX backend currently only supports a team // size of 1. @@ -242,7 +247,7 @@ public: member_type single_exec(*scheduler, member); member_type &team_exec = single_exec; - auto &team_queue = team_exec.scheduler().queue(); + auto &team_queue = team_exec.scheduler().queue(); task_base_type *task = no_more_tasks_sentinel; do { @@ -266,21 +271,21 @@ public: } } while (task != no_more_tasks_sentinel); - sem.signal(1); + num_tasks_remaining.count_down(1); }); } - sem.wait(num_worker_threads); + num_tasks_remaining.wait(); } template static void get_function_pointer(typename TaskType::function_type &ptr, typename TaskType::destroy_type &dtor) { - ptr = TaskType::apply; + ptr = TaskType::apply; dtor = TaskType::destroy; } -private: + private: const scheduler_type *scheduler; }; @@ -288,8 +293,8 @@ extern template class TaskQueue< Kokkos::Experimental::HPX, typename Kokkos::Experimental::HPX::memory_space>; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp index bbc1b33bf9..99020a3e0d 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIAvail.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Experimental::HPX -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp index aa1c2f1518..fae486f4b0 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_ViewCopyETIDecl.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,10 +49,9 @@ namespace Kokkos { namespace Impl { #define KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE Kokkos::Experimental::HPX -#include +#include #undef KOKKOS_IMPL_VIEWCOPY_ETI_AVAIL_EXECSPACE -} -} +} // namespace Impl +} // namespace Kokkos #endif - diff --git a/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp b/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp index 4dd28dd994..6705005c1b 100644 --- a/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp +++ b/lib/kokkos/core/src/HPX/Kokkos_HPX_WorkGraphPolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,8 +45,10 @@ #ifndef KOKKOS_HPX_WORKGRAPHPOLICY_HPP #define KOKKOS_HPX_WORKGRAPHPOLICY_HPP +#include + #include -#include +#include namespace Kokkos { namespace Impl { @@ -53,8 +56,8 @@ namespace Impl { template class ParallelFor, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::WorkGraphPolicy; + private: + using Policy = Kokkos::WorkGraphPolicy; using WorkTag = typename Policy::work_tag; Policy m_policy; @@ -73,7 +76,7 @@ private: m_functor(t, w); } -public: + public: void execute() const { dispatch_execute_task(this); Kokkos::Experimental::HPX().fence(); @@ -83,12 +86,13 @@ public: const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); for (int thread = 0; thread < num_worker_threads; ++thread) { - apply([this, &sem]() { + apply(exec, [this, &num_tasks_remaining]() { std::int32_t w = m_policy.pop_work(); while (w != Policy::COMPLETED_TOKEN) { if (w != Policy::END_TOKEN) { @@ -99,18 +103,18 @@ public: w = m_policy.pop_work(); } - sem.signal(1); + num_tasks_remaining.count_down(1); }); } - sem.wait(num_worker_threads); + num_tasks_remaining.wait(); } inline ParallelFor(const FunctorType &arg_functor, const Policy &arg_policy) : m_policy(arg_policy), m_functor(arg_functor) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif /* #define KOKKOS_HPX_WORKGRAPHPOLICY_HPP */ diff --git a/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp b/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp index 1972aa485b..7981c04b4f 100644 --- a/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp +++ b/lib/kokkos/core/src/KokkosExp_MDRangePolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,16 +49,16 @@ #include -#include +#include #include #include -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) -#include +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) +#include #include #endif -#if defined( __HCC__ ) && defined( KOKKOS_ENABLE_ROCM ) +#if defined(__HCC__) && defined(KOKKOS_ENABLE_ROCM) //#include #include #endif @@ -76,583 +77,613 @@ enum class Iterate */ template -struct default_outer_direction -{ +struct default_outer_direction { using type = Iterate; - #if defined( KOKKOS_ENABLE_CUDA)||defined( KOKKOS_ENABLE_ROCM) +#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_ROCM) static constexpr Iterate value = Iterate::Left; - #else +#else static constexpr Iterate value = Iterate::Right; - #endif +#endif }; template -struct default_inner_direction -{ +struct default_inner_direction { using type = Iterate; - #if defined( KOKKOS_ENABLE_CUDA)||defined( KOKKOS_ENABLE_ROCM) +#if defined(KOKKOS_ENABLE_CUDA) || defined(KOKKOS_ENABLE_ROCM) static constexpr Iterate value = Iterate::Left; - #else +#else static constexpr Iterate value = Iterate::Right; - #endif +#endif }; - // Iteration Pattern -template < unsigned N - , Iterate OuterDir = Iterate::Default - , Iterate InnerDir = Iterate::Default - > -struct Rank -{ - static_assert( N != 0u, "Kokkos Error: rank 0 undefined"); - static_assert( N != 1u, "Kokkos Error: rank 1 is not a multi-dimensional range"); - static_assert( N < 7u, "Kokkos Error: Unsupported rank..."); +template +struct Rank { + static_assert(N != 0u, "Kokkos Error: rank 0 undefined"); + static_assert(N != 1u, + "Kokkos Error: rank 1 is not a multi-dimensional range"); + static_assert(N < 7u, "Kokkos Error: Unsupported rank..."); using iteration_pattern = Rank; - static constexpr int rank = N; + static constexpr int rank = N; static constexpr Iterate outer_direction = OuterDir; static constexpr Iterate inner_direction = InnerDir; }; - // multi-dimensional iteration pattern template -struct MDRangePolicy - : public Kokkos::Impl::PolicyTraits -{ - using traits = Kokkos::Impl::PolicyTraits; +struct MDRangePolicy : public Kokkos::Impl::PolicyTraits { + using traits = Kokkos::Impl::PolicyTraits; using range_policy = RangePolicy; typename traits::execution_space m_space; - using impl_range_policy = RangePolicy< typename traits::execution_space - , typename traits::schedule_type - , typename traits::index_type - > ; + using impl_range_policy = + RangePolicy; - typedef MDRangePolicy execution_policy; // needed for is_execution_space interrogation + typedef MDRangePolicy + execution_policy; // needed for is_execution_space interrogation - template + template friend struct MDRangePolicy; - static_assert( !std::is_same::value - , "Kokkos Error: MD iteration pattern not defined" ); + static_assert(!std::is_same::value, + "Kokkos Error: MD iteration pattern not defined"); - using iteration_pattern = typename traits::iteration_pattern; - using work_tag = typename traits::work_tag; - using launch_bounds = typename traits::launch_bounds; - using member_type = typename range_policy::member_type; + using iteration_pattern = typename traits::iteration_pattern; + using work_tag = typename traits::work_tag; + using launch_bounds = typename traits::launch_bounds; + using member_type = typename range_policy::member_type; enum { rank = static_cast(iteration_pattern::rank) }; - using index_type = typename traits::index_type; + using index_type = typename traits::index_type; using array_index_type = long; - using point_type = Kokkos::Array; //was index_type - using tile_type = Kokkos::Array; - // If point_type or tile_type is not templated on a signed integral type (if it is unsigned), - // then if user passes in intializer_list of runtime-determined values of - // signed integral type that are not const will receive a compiler error due - // to an invalid case for implicit conversion - - // "conversion from integer or unscoped enumeration type to integer type that cannot represent all values of the original, except where source is a constant expression whose value can be stored exactly in the target type" + using point_type = Kokkos::Array; // was index_type + using tile_type = Kokkos::Array; + // If point_type or tile_type is not templated on a signed integral type (if + // it is unsigned), then if user passes in intializer_list of + // runtime-determined values of signed integral type that are not const will + // receive a compiler error due to an invalid case for implicit conversion - + // "conversion from integer or unscoped enumeration type to integer type that + // cannot represent all values of the original, except where source is a + // constant expression whose value can be stored exactly in the target type" // This would require the user to either pass a matching index_type parameter - // as template parameter to the MDRangePolicy or static_cast the individual values + // as template parameter to the MDRangePolicy or static_cast the individual + // values point_type m_lower; point_type m_upper; - tile_type m_tile; + tile_type m_tile; point_type m_tile_end; index_type m_num_tiles; index_type m_prod_tile_dims; -/* - // NDE enum impl definition alternative - replace static constexpr int ? - enum { outer_direction = static_cast ( - (iteration_pattern::outer_direction != Iterate::Default) - ? iteration_pattern::outer_direction - : default_outer_direction< typename traits::execution_space>::value ) }; + /* + // NDE enum impl definition alternative - replace static constexpr int ? + enum { outer_direction = static_cast ( + (iteration_pattern::outer_direction != Iterate::Default) + ? iteration_pattern::outer_direction + : default_outer_direction< typename traits::execution_space>::value ) }; - enum { inner_direction = static_cast ( - iteration_pattern::inner_direction != Iterate::Default - ? iteration_pattern::inner_direction - : default_inner_direction< typename traits::execution_space>::value ) }; + enum { inner_direction = static_cast ( + iteration_pattern::inner_direction != Iterate::Default + ? iteration_pattern::inner_direction + : default_inner_direction< typename traits::execution_space>::value ) }; - enum { Right = static_cast( Iterate::Right ) }; - enum { Left = static_cast( Iterate::Left ) }; -*/ - //static constexpr int rank = iteration_pattern::rank; + enum { Right = static_cast( Iterate::Right ) }; + enum { Left = static_cast( Iterate::Left ) }; + */ + // static constexpr int rank = iteration_pattern::rank; - static constexpr int outer_direction = static_cast ( + static constexpr int outer_direction = static_cast( (iteration_pattern::outer_direction != Iterate::Default) - ? iteration_pattern::outer_direction - : default_outer_direction< typename traits::execution_space>::value ); + ? iteration_pattern::outer_direction + : default_outer_direction::value); - static constexpr int inner_direction = static_cast ( + static constexpr int inner_direction = static_cast( iteration_pattern::inner_direction != Iterate::Default - ? iteration_pattern::inner_direction - : default_inner_direction< typename traits::execution_space>::value ) ; + ? iteration_pattern::inner_direction + : default_inner_direction::value); // Ugly ugly workaround intel 14 not handling scoped enum correctly - static constexpr int Right = static_cast( Iterate::Right ); - static constexpr int Left = static_cast( Iterate::Left ); + static constexpr int Right = static_cast(Iterate::Right); + static constexpr int Left = static_cast(Iterate::Left); - KOKKOS_INLINE_FUNCTION const typename traits::execution_space & space() const { return m_space ; } - template < typename LT , typename UT , typename TT = array_index_type > - MDRangePolicy(std::initializer_list const& lower, std::initializer_list const& upper, std::initializer_list const& tile = {} ) - : m_space() { + KOKKOS_INLINE_FUNCTION const typename traits::execution_space& space() const { + return m_space; + } + template + MDRangePolicy(std::initializer_list const& lower, + std::initializer_list const& upper, + std::initializer_list const& tile = {}) + : m_space() { init(lower, upper, tile); } - template < typename LT , typename UT , typename TT = array_index_type > - MDRangePolicy(const typename traits::execution_space & work_space, - std::initializer_list const& lower, std::initializer_list const& upper, std::initializer_list const& tile = {} ) - : m_space( work_space ) { + template + MDRangePolicy(const typename traits::execution_space& work_space, + std::initializer_list const& lower, + std::initializer_list const& upper, + std::initializer_list const& tile = {}) + : m_space(work_space) { init(lower, upper, tile); } - MDRangePolicy( point_type const& lower, point_type const& upper, tile_type const& tile = tile_type{} ) - : m_space() - , m_lower(lower) - , m_upper(upper) - , m_tile(tile) - , m_num_tiles(1) - , m_prod_tile_dims(1) { + MDRangePolicy(point_type const& lower, point_type const& upper, + tile_type const& tile = tile_type{}) + : m_space(), + m_lower(lower), + m_upper(upper), + m_tile(tile), + m_num_tiles(1), + m_prod_tile_dims(1) { init(); } - MDRangePolicy( const typename traits::execution_space & work_space, - point_type const& lower, point_type const& upper, tile_type const& tile = tile_type{} ) - : m_space( work_space ) - , m_lower(lower) - , m_upper(upper) - , m_tile(tile) - , m_num_tiles(1) - , m_prod_tile_dims(1) { + MDRangePolicy(const typename traits::execution_space& work_space, + point_type const& lower, point_type const& upper, + tile_type const& tile = tile_type{}) + : m_space(work_space), + m_lower(lower), + m_upper(upper), + m_tile(tile), + m_num_tiles(1), + m_prod_tile_dims(1) { init(); } - template - MDRangePolicy( const MDRangePolicy p ): - m_space(p.m_space), - m_lower(p.m_lower), - m_upper(p.m_upper), - m_tile(p.m_tile), - m_tile_end(p.m_tile_end), - m_num_tiles(p.m_num_tiles), - m_prod_tile_dims(p.m_prod_tile_dims) {} - -private: - + template + MDRangePolicy(const MDRangePolicy p) + : m_space(p.m_space), + m_lower(p.m_lower), + m_upper(p.m_upper), + m_tile(p.m_tile), + m_tile_end(p.m_tile_end), + m_num_tiles(p.m_num_tiles), + m_prod_tile_dims(p.m_prod_tile_dims) {} + + private: void init() { // Host - if ( true - #if defined(KOKKOS_ENABLE_CUDA) - && !std::is_same< typename traits::execution_space, Kokkos::Cuda >::value - #endif - #if defined(KOKKOS_ENABLE_ROCM) - && !std::is_same< typename traits::execution_space, Kokkos::Experimental::ROCm >::value - #endif - ) - { + if (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + ) { index_type span; - for (int i=0; i 0)) ) - { + if (m_tile[i] <= 0) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { m_tile[i] = 2; - } - else { + } else { m_tile[i] = (span == 0 ? 1 : span); } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } } - #if defined(KOKKOS_ENABLE_CUDA) - else // Cuda +#if defined(KOKKOS_ENABLE_CUDA) + else // Cuda { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for cuda // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 2; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 max per dim (Kepler), but product num_threads < 1024 + if (m_prod_tile_dims > + 1024) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 + // max per dim (Kepler), but product num_threads < 1024 printf(" Tile dimensions exceed Cuda limits\n"); - Kokkos::abort(" Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif - #if defined(KOKKOS_ENABLE_ROCM) - else // ROCm +#endif +#if defined(KOKKOS_ENABLE_ROCM) + else // ROCm { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for rocm // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 4; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { //but product num_threads < 1024 + if (m_prod_tile_dims > 1024) { // but product num_threads < 1024 printf(" Tile dimensions exceed ROCm limits\n"); - Kokkos::abort(" ROCm ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " ROCm ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif +#endif } - template < typename LT , typename UT , typename TT = array_index_type > - void init( std::initializer_list const& lower, std::initializer_list const& upper, std::initializer_list const& tile = {} ) - { - if(static_cast(m_lower.size()) != rank || static_cast(m_upper.size()) != rank) - Kokkos::abort("MDRangePolicy: Constructor initializer lists have wrong size"); + template + void init(std::initializer_list const& lower, + std::initializer_list const& upper, + std::initializer_list const& tile = {}) { + if (static_cast(m_lower.size()) != rank || + static_cast(m_upper.size()) != rank) + Kokkos::abort( + "MDRangePolicy: Constructor initializer lists have wrong size"); - for ( auto i = 0; i < rank; ++i ) { + for (auto i = 0; i < rank; ++i) { m_lower[i] = static_cast(lower.begin()[i]); m_upper[i] = static_cast(upper.begin()[i]); - if(static_cast(tile.size())==rank) + if (static_cast(tile.size()) == rank) m_tile[i] = static_cast(tile.begin()[i]); else m_tile[i] = 0; } - m_num_tiles = 1; + m_num_tiles = 1; m_prod_tile_dims = 1; // Host - if ( true - #if defined(KOKKOS_ENABLE_CUDA) - && !std::is_same< typename traits::execution_space, Kokkos::Cuda >::value - #endif - #if defined(KOKKOS_ENABLE_ROCM) - && !std::is_same< typename traits::execution_space, Kokkos::Experimental::ROCm >::value - #endif - ) - { + if (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + ) { index_type span; - for (int i=0; i 0)) ) - { + if (m_tile[i] <= 0) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { m_tile[i] = 2; - } - else { + } else { m_tile[i] = (span == 0 ? 1 : span); } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } } - #if defined(KOKKOS_ENABLE_CUDA) - else // Cuda +#if defined(KOKKOS_ENABLE_CUDA) + else // Cuda { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for cuda // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 2; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 max per dim (Kepler), but product num_threads < 1024 + if (m_prod_tile_dims > + 1024) { // Match Cuda restriction for ParallelReduce; 1024,1024,64 + // max per dim (Kepler), but product num_threads < 1024 printf(" Tile dimensions exceed Cuda limits\n"); - Kokkos::abort(" Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif - #if defined(KOKKOS_ENABLE_ROCM) - else // ROCm +#endif +#if defined(KOKKOS_ENABLE_ROCM) + else // ROCm { index_type span; - int increment = 1; + int increment = 1; int rank_start = 0; - int rank_end = rank; - if((int)inner_direction == (int)Right) { - increment = -1; - rank_start = rank-1; - rank_end = -1; + int rank_end = rank; + if ((int)inner_direction == (int)Right) { + increment = -1; + rank_start = rank - 1; + rank_end = -1; } - for (int i=rank_start; i!=rank_end; i+=increment) { + for (int i = rank_start; i != rank_end; i += increment) { span = m_upper[i] - m_lower[i]; - if ( m_tile[i] <= 0 ) { + if (m_tile[i] <= 0) { // TODO: determine what is a good default tile size for cuda // may be rank dependent - if ( ((int)inner_direction == (int)Right && (i < rank-1)) - || ((int)inner_direction == (int)Left && (i > 0)) ) - { - if ( m_prod_tile_dims < 256 ) { + if (((int)inner_direction == (int)Right && (i < rank - 1)) || + ((int)inner_direction == (int)Left && (i > 0))) { + if (m_prod_tile_dims < 256) { m_tile[i] = 2; } else { m_tile[i] = 1; } - } - else { + } else { m_tile[i] = 16; } } - m_tile_end[i] = static_cast((span + m_tile[i] - 1) / m_tile[i]); + m_tile_end[i] = + static_cast((span + m_tile[i] - 1) / m_tile[i]); m_num_tiles *= m_tile_end[i]; m_prod_tile_dims *= m_tile[i]; } - if ( m_prod_tile_dims > 1024 ) { // Match ROCm restriction for ParallelReduce; 1024,1024,1024 max per dim , but product num_threads < 1024 + if (m_prod_tile_dims > + 1024) { // Match ROCm restriction for ParallelReduce; 1024,1024,1024 + // max per dim , but product num_threads < 1024 printf(" Tile dimensions exceed ROCm limits\n"); - Kokkos::abort(" ROCm ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); - //Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: MDRange tile dims exceed maximum number of threads per block - choose smaller tile dims"); + Kokkos::abort( + " ROCm ExecSpace Error: MDRange tile dims exceed maximum number of " + "threads per block - choose smaller tile dims"); + // Kokkos::Impl::throw_runtime_exception( " Cuda ExecSpace Error: + // MDRange tile dims exceed maximum number of threads per block - choose + // smaller tile dims"); } } - #endif +#endif } - }; -} // namespace Kokkos +} // namespace Kokkos // For backward compatibility -namespace Kokkos { namespace Experimental { - using Kokkos::MDRangePolicy; - using Kokkos::Rank; - using Kokkos::Iterate; -} } // end Kokkos::Experimental +namespace Kokkos { +namespace Experimental { +using Kokkos::Iterate; +using Kokkos::MDRangePolicy; +using Kokkos::Rank; +} // namespace Experimental +} // namespace Kokkos // ------------------------------------------------------------------ // #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // ------------------------------------------------------------------ // -//md_parallel_for - deprecated use parallel_for +// md_parallel_for - deprecated use parallel_for // ------------------------------------------------------------------ // -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { template -void md_parallel_for( MDRange const& range - , Functor const& f - , const std::string& str = "" - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ +void md_parallel_for( + MDRange const& range, Functor const& f, const std::string& str = "", + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { Kokkos::Impl::Experimental::MDFunctor g(range, f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_for( range_policy(0, range.m_num_tiles).set_chunk_size(1), g, str ); + Kokkos::parallel_for(range_policy(0, range.m_num_tiles).set_chunk_size(1), g, + str); } template -void md_parallel_for( const std::string& str - , MDRange const& range - , Functor const& f - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ +void md_parallel_for( + const std::string& str, MDRange const& range, Functor const& f, + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { Kokkos::Impl::Experimental::MDFunctor g(range, f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_for( range_policy(0, range.m_num_tiles).set_chunk_size(1), g, str ); + Kokkos::parallel_for(range_policy(0, range.m_num_tiles).set_chunk_size(1), g, + str); } // Cuda specialization -#if defined( __CUDACC__ ) && defined( KOKKOS_ENABLE_CUDA ) +#if defined(__CUDACC__) && defined(KOKKOS_ENABLE_CUDA) template -void md_parallel_for( const std::string& str - , MDRange const& range - , Functor const& f - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::DeviceIterateTile closure(range, f); +void md_parallel_for( + const std::string& str, MDRange const& range, Functor const& f, + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::DeviceIterateTile + closure(range, f); closure.execute(); } template -void md_parallel_for( MDRange const& range - , Functor const& f - , const std::string& str = "" - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::DeviceIterateTile closure(range, f); +void md_parallel_for( + MDRange const& range, Functor const& f, const std::string& str = "", + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::DeviceIterateTile + closure(range, f); closure.execute(); } #endif // ------------------------------------------------------------------ // // ------------------------------------------------------------------ // -//md_parallel_reduce - deprecated use parallel_reduce +// md_parallel_reduce - deprecated use parallel_reduce // ------------------------------------------------------------------ // template -void md_parallel_reduce( MDRange const& range - , Functor const& f - , ValueType & v - , const std::string& str = "" - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::Experimental::MDFunctor g(range, f); +void md_parallel_reduce( + MDRange const& range, Functor const& f, ValueType& v, + const std::string& str = "", + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::Experimental::MDFunctor g(range, + f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_reduce( str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v ); + Kokkos::parallel_reduce( + str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v); } template -void md_parallel_reduce( const std::string& str - , MDRange const& range - , Functor const& f - , ValueType & v - , typename std::enable_if<( true - #if defined( KOKKOS_ENABLE_CUDA) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Cuda>::value - #endif - #if defined( KOKKOS_ENABLE_ROCM) - && !std::is_same< typename MDRange::range_policy::execution_space, Kokkos::Experimental::ROCm>::value - #endif - ) >::type* = 0 - ) -{ - Kokkos::Impl::Experimental::MDFunctor g(range, f); +void md_parallel_reduce( + const std::string& str, MDRange const& range, Functor const& f, + ValueType& v, + typename std::enable_if< + (true +#if defined(KOKKOS_ENABLE_CUDA) + && !std::is_same::value +#endif +#if defined(KOKKOS_ENABLE_ROCM) + && !std::is_same::value +#endif + )>::type* = 0) { + Kokkos::Impl::Experimental::MDFunctor g(range, + f); using range_policy = typename MDRange::impl_range_policy; - Kokkos::parallel_reduce( str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v ); + Kokkos::parallel_reduce( + str, range_policy(0, range.m_num_tiles).set_chunk_size(1), g, v); } // Cuda - md_parallel_reduce not implemented - use parallel_reduce -} } // namespace Kokkos::Experimental +} // namespace Experimental +} // namespace Kokkos #endif namespace Kokkos { namespace Experimental { namespace Impl { -template -struct PolicyPropertyAdaptor,MDRangePolicy> { +template +struct PolicyPropertyAdaptor, + MDRangePolicy> { typedef MDRangePolicy policy_in_t; typedef MDRangePolicy> policy_out_t; + typename policy_in_t::traits::schedule_type, + typename policy_in_t::traits::work_tag, + typename policy_in_t::traits::index_type, + typename policy_in_t::traits::iteration_pattern, + typename policy_in_t::traits::launch_bounds, + WorkItemProperty::ImplWorkItemProperty

> + policy_out_t; }; -} -} -} - - -#endif //KOKKOS_CORE_EXP_MD_RANGE_POLICY_HPP +} // namespace Impl +} // namespace Experimental +} // namespace Kokkos +#endif // KOKKOS_CORE_EXP_MD_RANGE_POLICY_HPP diff --git a/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp b/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp index c345158996..a4e887668f 100644 --- a/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_AnonymousSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -53,28 +54,28 @@ namespace Kokkos { class AnonymousSpace { -public: + public: //! Tag this class as a kokkos memory space - typedef AnonymousSpace memory_space; + typedef AnonymousSpace memory_space; typedef Kokkos::DefaultExecutionSpace execution_space; - typedef size_t size_type; + typedef size_t size_type; //! This memory space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; /**\brief Default memory space instance */ - AnonymousSpace() = default; - AnonymousSpace( AnonymousSpace && rhs ) = default; - AnonymousSpace( const AnonymousSpace & rhs ) = default; - AnonymousSpace & operator = ( AnonymousSpace && ) = default; - AnonymousSpace & operator = ( const AnonymousSpace & ) = default; - ~AnonymousSpace() = default; + AnonymousSpace() = default; + AnonymousSpace(AnonymousSpace &&rhs) = default; + AnonymousSpace(const AnonymousSpace &rhs) = default; + AnonymousSpace &operator=(AnonymousSpace &&) = default; + AnonymousSpace &operator=(const AnonymousSpace &) = default; + ~AnonymousSpace() = default; /**\brief Return Name of the MemorySpace */ - static constexpr const char* name() { return "Anonymous"; } + static constexpr const char *name() { return "Anonymous"; } }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -82,46 +83,43 @@ namespace Kokkos { namespace Impl { -template -struct MemorySpaceAccess< Kokkos::AnonymousSpace , OtherSpace > { +template +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template -struct MemorySpaceAccess< OtherSpace, Kokkos::AnonymousSpace > { +template +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::AnonymousSpace, Kokkos::AnonymousSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template -struct VerifyExecutionCanAccessMemorySpace -{ - enum {value = 1}; +template +struct VerifyExecutionCanAccessMemorySpace { + enum { value = 1 }; KOKKOS_INLINE_FUNCTION static void verify(void) {} KOKKOS_INLINE_FUNCTION static void verify(const void *) {} }; -template -struct VerifyExecutionCanAccessMemorySpace -{ - enum {value = 1}; +template +struct VerifyExecutionCanAccessMemorySpace { + enum { value = 1 }; KOKKOS_INLINE_FUNCTION static void verify(void) {} KOKKOS_INLINE_FUNCTION static void verify(const void *) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos - -#endif // #define KOKKOS_ANONYMOUSSPACE_HPP +} // namespace Kokkos +#endif // #define KOKKOS_ANONYMOUSSPACE_HPP diff --git a/lib/kokkos/core/src/Kokkos_Array.hpp b/lib/kokkos/core/src/Kokkos_Array.hpp index 8e5862fe9c..88e7883cb9 100644 --- a/lib/kokkos/core/src/Kokkos_Array.hpp +++ b/lib/kokkos/core/src/Kokkos_Array.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -82,7 +83,7 @@ template struct ArrayBoundsCheck { KOKKOS_INLINE_FUNCTION ArrayBoundsCheck(Integral i, size_t N) { - if ( size_t(i) >= N) { + if (size_t(i) >= N) { #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST std::string s = "Kokkos::Array: index "; s += std::to_string(i); @@ -95,7 +96,7 @@ struct ArrayBoundsCheck { } } }; -} // end namespace Impl +} // end namespace Impl #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) \ Kokkos::Impl::ArrayBoundsCheck(i, N) @@ -104,17 +105,14 @@ struct ArrayBoundsCheck { #define KOKKOS_ARRAY_BOUNDS_CHECK(i, N) (void)0 -#endif // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) +#endif // !defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) /**\brief Derived from the C++17 'std::array'. * Dropping the iterator interface. */ -template< class T = void - , size_t N =KOKKOS_INVALID_INDEX - , class Proxy = void - > +template struct Array { -public: + public: /** * The elements of this C array shall not be accessed directly. The data * member has to be declared public to enable aggregate initialization as for @@ -122,115 +120,113 @@ public: * @private */ T m_internal_implementation_private_member_data[N]; -public: - typedef T & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef T value_type ; - typedef T * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return N ; } - KOKKOS_INLINE_FUNCTION static constexpr bool empty(){ return false ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return N ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - reference operator[]( const iType & i ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, N); - return m_internal_implementation_private_member_data[i]; - } + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return N; } + KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return false; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return N; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, N); + return m_internal_implementation_private_member_data[i]; + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - const_reference operator[]( const iType & i ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, N); - return m_internal_implementation_private_member_data[i]; - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, N); + return m_internal_implementation_private_member_data[i]; + } - KOKKOS_INLINE_FUNCTION pointer data() - { - return & m_internal_implementation_private_member_data[0]; - } - KOKKOS_INLINE_FUNCTION const_pointer data() const - { - return & m_internal_implementation_private_member_data[0]; - } + KOKKOS_INLINE_FUNCTION pointer data() { + return &m_internal_implementation_private_member_data[0]; + } + KOKKOS_INLINE_FUNCTION const_pointer data() const { + return &m_internal_implementation_private_member_data[0]; + } - #ifdef KOKKOS_IMPL_ROCM_CLANG_WORKAROUND +#ifdef KOKKOS_IMPL_ROCM_CLANG_WORKAROUND // Do not default unless move and move-assignment are also defined KOKKOS_INLINE_FUNCTION - ~Array() = default ; - Array() = default ; - Array( const Array & ) = default ; - Array & operator = ( const Array & ) = default ; + ~Array() = default; + Array() = default; + Array(const Array&) = default; + Array& operator=(const Array&) = default; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. - Array( Array && ) = default ; - Array & operator = ( Array && ) = default ; - + Array(Array&&) = default; + Array& operator=(Array&&) = default; + KOKKOS_INLINE_FUNCTION Array(const std::initializer_list& vals) { - for(int i=0; i +struct Array { + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0; } + KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType&) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integer argument"); + Kokkos::abort("Unreachable code"); + return *reinterpret_cast(-1); + } -template< class T , class Proxy > -struct Array { -public: - - typedef typename std::add_const::type & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef typename std::add_const::type value_type ; - typedef typename std::add_const::type * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION static constexpr size_type size() { return 0 ; } - KOKKOS_INLINE_FUNCTION static constexpr bool empty() { return true ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return 0 ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - value_type operator[]( const iType & ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integer argument" ); - return value_type(); - } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - value_type operator[]( const iType & ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integer argument" ); - return value_type(); - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType&) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integer argument"); + Kokkos::abort("Unreachable code"); + return *reinterpret_cast(-1); + } - KOKKOS_INLINE_FUNCTION pointer data() { return pointer(0) ; } + KOKKOS_INLINE_FUNCTION pointer data() { return pointer(0); } KOKKOS_INLINE_FUNCTION const_pointer data() const { return const_pointer(0); } #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION ~Array() {} KOKKOS_INLINE_FUNCTION Array() {} - KOKKOS_INLINE_FUNCTION Array( const Array & ) {} - KOKKOS_INLINE_FUNCTION Array & operator = ( const Array & ) {} + KOKKOS_INLINE_FUNCTION Array(const Array&) {} + KOKKOS_INLINE_FUNCTION Array& operator=(const Array&) {} #else - KOKKOS_INLINE_FUNCTION ~Array() = default; - KOKKOS_INLINE_FUNCTION Array() = default; - KOKKOS_INLINE_FUNCTION Array( const Array & ) = default; - KOKKOS_INLINE_FUNCTION Array & operator = ( const Array & ) = default; + KOKKOS_INLINE_FUNCTION ~Array() = default; + KOKKOS_INLINE_FUNCTION Array() = default; + KOKKOS_INLINE_FUNCTION Array(const Array&) = default; + KOKKOS_INLINE_FUNCTION Array& operator=(const Array&) = default; #endif // Some supported compilers are not sufficiently C++11 compliant @@ -239,62 +235,59 @@ public: // Array & operator = ( Array && ) = default ; }; - -template<> -struct Array -{ +template <> +struct Array { struct contiguous {}; struct strided {}; }; -template< class T > -struct Array< T ,KOKKOS_INVALID_INDEX , Array<>::contiguous > -{ -private: - T * m_elem ; - size_t m_size ; -public: - - typedef T & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef T value_type ; - typedef T * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size ; } - KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - reference operator[]( const iType & i ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i]; - } +template +struct Array::contiguous> { + private: + T* m_elem; + size_t m_size; + + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; } + KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i]; + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - const_reference operator[]( const iType & i ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i]; - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i]; + } - KOKKOS_INLINE_FUNCTION pointer data() { return m_elem ; } - KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem ; } + KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; } + KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; } #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION ~Array() {} #else - KOKKOS_INLINE_FUNCTION ~Array() = default; + KOKKOS_INLINE_FUNCTION ~Array() = default; #endif - Array() = delete ; - Array( const Array & rhs ) = delete ; + Array() = delete; + Array(const Array& rhs) = delete; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. @@ -302,76 +295,72 @@ public: // Array & operator = ( Array && rhs ) = delete ; KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - template< size_t N , class P > - KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + template + KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - KOKKOS_INLINE_FUNCTION constexpr Array( pointer arg_ptr , size_type arg_size , size_type = 0 ) - : m_elem(arg_ptr), m_size(arg_size) {} + KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size, + size_type = 0) + : m_elem(arg_ptr), m_size(arg_size) {} }; -template< class T > -struct Array< T ,KOKKOS_INVALID_INDEX , Array<>::strided > -{ -private: - T * m_elem ; - size_t m_size ; - size_t m_stride ; -public: - - typedef T & reference ; - typedef typename std::add_const::type & const_reference ; - typedef size_t size_type ; - typedef ptrdiff_t difference_type ; - typedef T value_type ; - typedef T * pointer ; - typedef typename std::add_const::type * const_pointer ; - - KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size ; } - KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size ; } - KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size ; } - - template< typename iType > - KOKKOS_INLINE_FUNCTION - reference operator[]( const iType & i ) - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i*m_stride]; - } +template +struct Array::strided> { + private: + T* m_elem; + size_t m_size; + size_t m_stride; + + public: + typedef T& reference; + typedef typename std::add_const::type& const_reference; + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T value_type; + typedef T* pointer; + typedef typename std::add_const::type* const_pointer; + + KOKKOS_INLINE_FUNCTION constexpr size_type size() const { return m_size; } + KOKKOS_INLINE_FUNCTION constexpr bool empty() const { return 0 != m_size; } + KOKKOS_INLINE_FUNCTION constexpr size_type max_size() const { return m_size; } + + template + KOKKOS_INLINE_FUNCTION reference operator[](const iType& i) { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i * m_stride]; + } - template< typename iType > - KOKKOS_INLINE_FUNCTION - const_reference operator[]( const iType & i ) const - { - static_assert( ( std::is_integral::value || std::is_enum::value ) , "Must be integral argument" ); - KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); - return m_elem[i*m_stride]; - } + template + KOKKOS_INLINE_FUNCTION const_reference operator[](const iType& i) const { + static_assert( + (std::is_integral::value || std::is_enum::value), + "Must be integral argument"); + KOKKOS_ARRAY_BOUNDS_CHECK(i, m_size); + return m_elem[i * m_stride]; + } - KOKKOS_INLINE_FUNCTION pointer data() { return m_elem ; } - KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem ; } + KOKKOS_INLINE_FUNCTION pointer data() { return m_elem; } + KOKKOS_INLINE_FUNCTION const_pointer data() const { return m_elem; } #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND KOKKOS_INLINE_FUNCTION ~Array() {} #else - KOKKOS_INLINE_FUNCTION ~Array() = default; + KOKKOS_INLINE_FUNCTION ~Array() = default; #endif - Array() = delete ; - Array( const Array & ) = delete ; - + Array() = delete; + Array(const Array&) = delete; // Some supported compilers are not sufficiently C++11 compliant // for default move constructor and move assignment operator. @@ -379,27 +368,24 @@ public: // Array & operator = ( Array && rhs ) = delete ; KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - template< size_t N , class P > - KOKKOS_INLINE_FUNCTION - Array & operator = ( const Array & rhs ) - { - const size_t n = std::min( m_size , rhs.size() ); - for ( size_t i = 0 ; i < n ; ++i ) m_elem[i] = rhs[i] ; - return *this ; - } + template + KOKKOS_INLINE_FUNCTION Array& operator=(const Array& rhs) { + const size_t n = std::min(m_size, rhs.size()); + for (size_t i = 0; i < n; ++i) m_elem[i] = rhs[i]; + return *this; + } - KOKKOS_INLINE_FUNCTION constexpr Array( pointer arg_ptr , size_type arg_size , size_type arg_stride ) - : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {} + KOKKOS_INLINE_FUNCTION constexpr Array(pointer arg_ptr, size_type arg_size, + size_type arg_stride) + : m_elem(arg_ptr), m_size(arg_size), m_stride(arg_stride) {} }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_ARRAY_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Atomic.hpp b/lib/kokkos/core/src/Kokkos_Atomic.hpp index c2268bd35f..c4f7fa3ec1 100644 --- a/lib/kokkos/core/src/Kokkos_Atomic.hpp +++ b/lib/kokkos/core/src/Kokkos_Atomic.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -75,7 +76,7 @@ #if defined(_WIN32) #define KOKKOS_ENABLE_WINDOWS_ATOMICS #else -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) // Compiling NVIDIA device code, must use Cuda atomics: @@ -87,32 +88,30 @@ #endif -#if ! defined( KOKKOS_ENABLE_GNU_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_INTEL_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_OPENMP_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_STD_ATOMICS ) && \ - ! defined( KOKKOS_ENABLE_SERIAL_ATOMICS ) +#if !defined(KOKKOS_ENABLE_GNU_ATOMICS) && \ + !defined(KOKKOS_ENABLE_INTEL_ATOMICS) && \ + !defined(KOKKOS_ENABLE_OPENMP_ATOMICS) && \ + !defined(KOKKOS_ENABLE_STD_ATOMICS) && \ + !defined(KOKKOS_ENABLE_SERIAL_ATOMICS) // Compiling for non-Cuda atomic implementation has not been pre-selected. // Choose the best implementation for the detected compiler. // Preference: GCC, INTEL, OMP31 -#if defined( KOKKOS_INTERNAL_NOT_PARALLEL ) +#if defined(KOKKOS_INTERNAL_NOT_PARALLEL) #define KOKKOS_ENABLE_SERIAL_ATOMICS -#elif defined( KOKKOS_COMPILER_GNU ) || \ - defined( KOKKOS_COMPILER_CLANG ) || \ - ( defined ( KOKKOS_COMPILER_NVCC ) ) +#elif defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) || \ + (defined(KOKKOS_COMPILER_NVCC)) #define KOKKOS_ENABLE_GNU_ATOMICS -#elif defined( KOKKOS_COMPILER_INTEL ) || \ - defined( KOKKOS_COMPILER_CRAYC ) +#elif defined(KOKKOS_COMPILER_INTEL) || defined(KOKKOS_COMPILER_CRAYC) #define KOKKOS_ENABLE_INTEL_ATOMICS -#elif defined( _OPENMP ) && ( 201107 <= _OPENMP ) +#elif defined(_OPENMP) && (201107 <= _OPENMP) #define KOKKOS_ENABLE_OPENMP_ATOMICS @@ -131,43 +130,37 @@ namespace Kokkos { template -KOKKOS_INLINE_FUNCTION -void atomic_add(volatile T * const dest, const T src); +KOKKOS_INLINE_FUNCTION void atomic_add(volatile T* const dest, const T src); // Atomic increment -template -KOKKOS_INLINE_FUNCTION -void atomic_increment(volatile T* a); +template +KOKKOS_INLINE_FUNCTION void atomic_increment(volatile T* a); -template -KOKKOS_INLINE_FUNCTION -void atomic_decrement(volatile T* a); -} +template +KOKKOS_INLINE_FUNCTION void atomic_decrement(volatile T* a); +} // namespace Kokkos namespace Kokkos { - -inline -const char * atomic_query_version() -{ -#if defined( KOKKOS_ENABLE_CUDA_ATOMICS ) - return "KOKKOS_ENABLE_CUDA_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_GNU_ATOMICS ) - return "KOKKOS_ENABLE_GNU_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_INTEL_ATOMICS ) - return "KOKKOS_ENABLE_INTEL_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_OPENMP_ATOMICS ) - return "KOKKOS_ENABLE_OPENMP_ATOMICS" ; -#elif defined( KOKKOS_ENABLE_WINDOWS_ATOMICS ) +inline const char* atomic_query_version() { +#if defined(KOKKOS_ENABLE_CUDA_ATOMICS) + return "KOKKOS_ENABLE_CUDA_ATOMICS"; +#elif defined(KOKKOS_ENABLE_GNU_ATOMICS) + return "KOKKOS_ENABLE_GNU_ATOMICS"; +#elif defined(KOKKOS_ENABLE_INTEL_ATOMICS) + return "KOKKOS_ENABLE_INTEL_ATOMICS"; +#elif defined(KOKKOS_ENABLE_OPENMP_ATOMICS) + return "KOKKOS_ENABLE_OPENMP_ATOMICS"; +#elif defined(KOKKOS_ENABLE_WINDOWS_ATOMICS) return "KOKKOS_ENABLE_WINDOWS_ATOMICS"; -#elif defined( KOKKOS_ENABLE_SERIAL_ATOMICS ) +#elif defined(KOKKOS_ENABLE_SERIAL_ATOMICS) return "KOKKOS_ENABLE_SERIAL_ATOMICS"; #else #error "No valid response for atomic_query_version!" #endif } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Atomic Memory Orders @@ -175,16 +168,14 @@ const char * atomic_query_version() // Implements Strongly-typed analogs of C++ standard memory orders #include "impl/Kokkos_Atomic_Memory_Order.hpp" -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) namespace Kokkos { namespace Impl { -extern KOKKOS_INLINE_FUNCTION -bool lock_address_rocm_space(void* ptr); +extern KOKKOS_INLINE_FUNCTION bool lock_address_rocm_space(void* ptr); -extern KOKKOS_INLINE_FUNCTION -void unlock_address_rocm_space(void* ptr); -} -} +extern KOKKOS_INLINE_FUNCTION void unlock_address_rocm_space(void* ptr); +} // namespace Impl +} // namespace Kokkos #include #endif @@ -212,8 +203,9 @@ void unlock_address_rocm_space(void* ptr); // Atomic compare-and-exchange // // template -// bool atomic_compare_exchange_strong(volatile T* const dest, const T compare, const T val) -// { bool equal = compare == *dest ; if ( equal ) { *dest = val ; } return equal ; } +// bool atomic_compare_exchange_strong(volatile T* const dest, const T compare, +// const T val) { bool equal = compare == *dest ; if ( equal ) { *dest = val ; } +// return equal ; } #include "impl/Kokkos_Atomic_Compare_Exchange_Strong.hpp" @@ -275,7 +267,8 @@ void unlock_address_rocm_space(void* ptr); //---------------------------------------------------------------------------- // Memory fence // -// All loads and stores from this thread will be globally consistent before continuing +// All loads and stores from this thread will be globally consistent before +// continuing // // void memory_fence() {...}; #include "impl/Kokkos_Memory_Fence.hpp" @@ -301,23 +294,22 @@ void unlock_address_rocm_space(void* ptr); #include "impl/Kokkos_Atomic_Load.hpp" #include "impl/Kokkos_Atomic_Store.hpp" - //---------------------------------------------------------------------------- // This atomic-style macro should be an inlined function, not a macro -#if defined( KOKKOS_COMPILER_GNU ) && !defined(__PGIC__) && !defined(__CUDA_ARCH__) +#if defined(KOKKOS_COMPILER_GNU) && !defined(__PGIC__) && \ + !defined(__CUDA_ARCH__) - #define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) __builtin_prefetch(addr,0,0) - #define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) __builtin_prefetch(addr,1,0) +#define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) __builtin_prefetch(addr, 0, 0) +#define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) __builtin_prefetch(addr, 1, 0) #else - #define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) ((void)0) - #define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) ((void)0) +#define KOKKOS_NONTEMPORAL_PREFETCH_LOAD(addr) ((void)0) +#define KOKKOS_NONTEMPORAL_PREFETCH_STORE(addr) ((void)0) #endif //---------------------------------------------------------------------------- #endif /* KOKKOS_ATOMIC_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Complex.hpp b/lib/kokkos/core/src/Kokkos_Complex.hpp index a3ada5d55e..a9af073b41 100644 --- a/lib/kokkos/core/src/Kokkos_Complex.hpp +++ b/lib/kokkos/core/src/Kokkos_Complex.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,658 +58,683 @@ namespace Kokkos { /// complex number. As with std::complex, this is only defined for /// \c float, \c double, and long double. The latter is /// currently forbidden in CUDA device kernels. -template -class complex { -private: - RealType re_, im_; +template +class +#ifdef KOKKOS_ENABLE_COMPLEX_ALIGN + alignas(2 * sizeof(RealType)) +#endif + complex { + private: + RealType re_{}; + RealType im_{}; -public: + public: //! The type of the real or imaginary parts of this complex number. - typedef RealType value_type; + using value_type = RealType; //! Default constructor (initializes both real and imaginary parts to zero). - KOKKOS_INLINE_FUNCTION complex () : - re_ (0.0), im_ (0.0) - {} + KOKKOS_INLINE_FUNCTION + complex() noexcept = default; //! Copy constructor. - KOKKOS_INLINE_FUNCTION complex (const complex& src) : - re_ (src.re_), im_ (src.im_) - {} + KOKKOS_INLINE_FUNCTION + complex(const complex&) noexcept = default; - //! Copy constructor from volatile. - KOKKOS_INLINE_FUNCTION complex (const volatile complex& src) : - re_ (src.re_), im_ (src.im_) - {} + KOKKOS_INLINE_FUNCTION + complex& operator=(const complex&) noexcept = default; + + /// \brief Conversion constructor from compatible RType + template ::value, + int>::type = 0> + KOKKOS_INLINE_FUNCTION complex(const complex& other) noexcept + // Intentionally do the conversions implicitly here so that users don't + // get any warnings about narrowing, etc., that they would expect to get + // otherwise. + : re_(other.real()), im_(other.imag()) {} /// \brief Conversion constructor from std::complex. /// /// This constructor cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. - template - complex (const std::complex& src) : - re_ (std::real (src)), im_ (std::imag (src)) - {} + KOKKOS_INLINE_FUNCTION + complex(const std::complex& src) noexcept + // We can use this aspect of the standard to avoid calling + // non-device-marked functions `std::real` and `std::imag`: "For any + // object z of type complex, reinterpret_cast(z)[0] is the + // real part of z and reinterpret_cast(z)[1] is the imaginary + // part of z." Now we don't have to provide a whole bunch of the overloads + // of things taking either Kokkos::complex or std::complex + : re_(reinterpret_cast(src)[0]), + im_(reinterpret_cast(src)[1]) {} /// \brief Conversion operator to std::complex. /// /// This operator cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. - operator std::complex () const { - return std::complex (re_, im_); + // TODO: make explicit. DJS 2019-08-28 + operator std::complex() const noexcept { + return std::complex(re_, im_); } /// \brief Constructor that takes just the real part, and sets the /// imaginary part to zero. - template - KOKKOS_INLINE_FUNCTION complex (const InputRealType& val) : - re_ (val), im_ (static_cast(0.0)) - {} - - // BUG HCC WORKAROUND - KOKKOS_INLINE_FUNCTION complex( const RealType& re, const RealType& im): - re_ (re), im_ (im) - {} - - //! Constructor that takes the real and imaginary parts. - template - KOKKOS_INLINE_FUNCTION complex (const RealType1& re, const RealType2& im) : - re_ (re), im_ (im) - {} + KOKKOS_INLINE_FUNCTION complex(const RealType& val) noexcept + : re_(val), im_(static_cast(0)) {} - //! Assignment operator. - template - KOKKOS_INLINE_FUNCTION - complex& operator= (const complex& src) { - re_ = src.re_; - im_ = src.im_; - return *this; - } - - /// \brief Assignment operator, for volatile *this and - /// nonvolatile input. - /// - /// \param src [in] Input; right-hand side of the assignment. - /// - /// This operator returns \c void instead of volatile - /// complex& . See Kokkos Issue #177 for the - /// explanation. In practice, this means that you should not chain - /// assignments with volatile lvalues. - template - KOKKOS_INLINE_FUNCTION - void operator= (const complex& src) volatile { - re_ = src.re_; - im_ = src.im_; - // We deliberately do not return anything here. See explanation - // in public documentation above. - } - - //! Assignment operator. - template - KOKKOS_INLINE_FUNCTION - volatile complex& operator= (const volatile complex& src) volatile { - re_ = src.re_; - im_ = src.im_; - return *this; - } - - //! Assignment operator. - template + //! Constructor that takes the real and imaginary parts. KOKKOS_INLINE_FUNCTION - complex& operator= (const volatile complex& src) { - re_ = src.re_; - im_ = src.im_; - return *this; - } + complex(const RealType& re, const RealType& im) noexcept : re_(re), im_(im) {} //! Assignment operator (from a real number). - template - KOKKOS_INLINE_FUNCTION - complex& operator= (const InputRealType& val) { + KOKKOS_INLINE_FUNCTION complex& operator=(const RealType& val) noexcept { re_ = val; - im_ = static_cast (0.0); + im_ = RealType(0); return *this; } - //! Assignment operator (from a real number). - template - KOKKOS_INLINE_FUNCTION - void operator= (const InputRealType& val) volatile { - re_ = val; - im_ = static_cast (0.0); - } - /// \brief Assignment operator from std::complex. /// /// This constructor cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. - template - complex& operator= (const std::complex& src) { - re_ = std::real (src); - im_ = std::imag (src); + complex& operator=(const std::complex& src) noexcept { + *this = complex(src); return *this; } //! The imaginary part of this complex number. - KOKKOS_INLINE_FUNCTION RealType& imag () { - return im_; - } + KOKKOS_INLINE_FUNCTION + KOKKOS_CONSTEXPR_14 RealType& imag() noexcept { return im_; } //! The real part of this complex number. - KOKKOS_INLINE_FUNCTION RealType& real () { - return re_; - } + KOKKOS_INLINE_FUNCTION + KOKKOS_CONSTEXPR_14 RealType& real() noexcept { return re_; } //! The imaginary part of this complex number. - KOKKOS_INLINE_FUNCTION const RealType imag () const { - return im_; - } + KOKKOS_INLINE_FUNCTION + constexpr RealType imag() const noexcept { return im_; } //! The real part of this complex number. - KOKKOS_INLINE_FUNCTION const RealType real () const { - return re_; - } - - //! The imaginary part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION volatile RealType& imag () volatile { - return im_; - } - - //! The real part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION volatile RealType& real () volatile { - return re_; - } - - //! The imaginary part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION const RealType imag () const volatile { - return im_; - } - - //! The real part of this complex number (volatile overload). - KOKKOS_INLINE_FUNCTION const RealType real () const volatile { - return re_; - } + KOKKOS_INLINE_FUNCTION + constexpr RealType real() const noexcept { return re_; } //! Set the imaginary part of this complex number. - KOKKOS_INLINE_FUNCTION void imag (RealType v) { - im_ = v; - } + KOKKOS_INLINE_FUNCTION + KOKKOS_CONSTEXPR_14 + void imag(RealType v) noexcept { im_ = v; } //! Set the real part of this complex number. - KOKKOS_INLINE_FUNCTION void real (RealType v) { - re_ = v; - } - - template KOKKOS_INLINE_FUNCTION - complex& - operator += (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - re_ += src.re_; - im_ += src.im_; - return *this; - } + KOKKOS_CONSTEXPR_14 + void real(RealType v) noexcept { re_ = v; } - template - KOKKOS_INLINE_FUNCTION - void - operator += (const volatile complex& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator+=( + const complex& src) noexcept { re_ += src.re_; im_ += src.im_; - } - - KOKKOS_INLINE_FUNCTION - complex& - operator += (const std::complex& src) { - re_ += src.real(); - im_ += src.imag(); return *this; } - template - KOKKOS_INLINE_FUNCTION - complex& - operator += (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator+=( + const RealType& src) noexcept { re_ += src; return *this; } - template - KOKKOS_INLINE_FUNCTION - void - operator += (const volatile InputRealType& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - re_ += src; - } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator -= (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator-=( + const complex& src) noexcept { re_ -= src.re_; im_ -= src.im_; return *this; } - KOKKOS_INLINE_FUNCTION - complex& - operator -= (const std::complex& src) { - re_ -= src.real(); - im_ -= src.imag(); - return *this; - } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator -= (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator-=( + const RealType& src) noexcept { re_ -= src; return *this; } - template - KOKKOS_INLINE_FUNCTION - complex& - operator *= (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - const RealType realPart = re_ * src.re_ - im_ * src.im_; - const RealType imagPart = re_ * src.im_ + im_ * src.re_; - re_ = realPart; - im_ = imagPart; - return *this; - } - - template - KOKKOS_INLINE_FUNCTION - void - operator *= (const volatile complex& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator*=( + const complex& src) noexcept { const RealType realPart = re_ * src.re_ - im_ * src.im_; const RealType imagPart = re_ * src.im_ + im_ * src.re_; - re_ = realPart; - im_ = imagPart; - } - - KOKKOS_INLINE_FUNCTION - complex& - operator *= (const std::complex& src) { - const RealType realPart = re_ * src.real() - im_ * src.imag(); - const RealType imagPart = re_ * src.imag() + im_ * src.real(); - re_ = realPart; - im_ = imagPart; + re_ = realPart; + im_ = imagPart; return *this; } - template - KOKKOS_INLINE_FUNCTION - complex& - operator *= (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator*=( + const RealType& src) noexcept { re_ *= src; im_ *= src; return *this; } - template - KOKKOS_INLINE_FUNCTION - void - operator *= (const volatile InputRealType& src) volatile { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - re_ *= src; - im_ *= src; - } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator /= (const complex& y) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - + // Conditional noexcept, just in case RType throws on divide-by-zero + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator/=( + const complex& y) noexcept(noexcept(RealType{} / RealType{})) { // Scale (by the "1-norm" of y) to avoid unwarranted overflow. // If the real part is +/-Inf and the imaginary part is -/+Inf, // this won't change the result. - const RealType s = std::fabs (y.real ()) + std::fabs (y.imag ()); + const RealType s = std::fabs(y.real()) + std::fabs(y.imag()); // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0. // In that case, the relation x/y == (x/s) / (y/s) doesn't hold, // because y/s is NaN. - if (s == 0.0) { + // TODO mark this branch unlikely + if (s == RealType(0)) { this->re_ /= s; this->im_ /= s; - } - else { - const complex x_scaled (this->re_ / s, this->im_ / s); - const complex y_conj_scaled (y.re_ / s, -(y.im_) / s); - const RealType y_scaled_abs = y_conj_scaled.re_ * y_conj_scaled.re_ + - y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) + } else { + const complex x_scaled(this->re_ / s, this->im_ / s); + const complex y_conj_scaled(y.re_ / s, -(y.im_) / s); + const RealType y_scaled_abs = + y_conj_scaled.re_ * y_conj_scaled.re_ + + y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) *this = x_scaled * y_conj_scaled; *this /= y_scaled_abs; } return *this; } - - KOKKOS_INLINE_FUNCTION - complex& - operator /= (const std::complex& y) { + KOKKOS_CONSTEXPR_14 + KOKKOS_INLINE_FUNCTION complex& operator/=( + const std::complex& y) noexcept(noexcept(RealType{} / + RealType{})) { // Scale (by the "1-norm" of y) to avoid unwarranted overflow. // If the real part is +/-Inf and the imaginary part is -/+Inf, // this won't change the result. - const RealType s = std::fabs (y.real ()) + std::fabs (y.imag ()); + const RealType s = std::fabs(y.real()) + std::fabs(y.imag()); // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0. // In that case, the relation x/y == (x/s) / (y/s) doesn't hold, // because y/s is NaN. - if (s == 0.0) { + if (s == RealType(0)) { this->re_ /= s; this->im_ /= s; - } - else { - const complex x_scaled (this->re_ / s, this->im_ / s); - const complex y_conj_scaled (y.re_ / s, -(y.im_) / s); - const RealType y_scaled_abs = y_conj_scaled.re_ * y_conj_scaled.re_ + - y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) + } else { + const complex x_scaled(this->re_ / s, this->im_ / s); + const complex y_conj_scaled(y.re_ / s, -(y.im_) / s); + const RealType y_scaled_abs = + y_conj_scaled.re_ * y_conj_scaled.re_ + + y_conj_scaled.im_ * y_conj_scaled.im_; // abs(y) == abs(conj(y)) *this = x_scaled * y_conj_scaled; *this /= y_scaled_abs; } return *this; } - - template - KOKKOS_INLINE_FUNCTION - complex& - operator /= (const InputRealType& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); - + KOKKOS_CONSTEXPR_14 KOKKOS_INLINE_FUNCTION complex& operator/=( + const RealType& src) noexcept(noexcept(RealType{} / RealType{})) { re_ /= src; im_ /= src; return *this; } - template - KOKKOS_INLINE_FUNCTION - bool - operator == (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + //--------------------------------------------------------------------------- + // TODO: refactor Kokkos reductions to remove dependency on + // volatile member overloads since they are being deprecated in c++20 + //--------------------------------------------------------------------------- + + //! Copy constructor from volatile. + template ::value, + int>::type = 0> + KOKKOS_INLINE_FUNCTION complex(const volatile complex& src) noexcept + // Intentionally do the conversions implicitly here so that users don't + // get any warnings about narrowing, etc., that they would expect to get + // otherwise. + : re_(src.re_), im_(src.im_) {} - return (re_ == static_cast(src.re_)) && (im_ == static_cast(src.im_)); + /// \brief Assignment operator, for volatile *this and + /// nonvolatile input. + /// + /// \param src [in] Input; right-hand side of the assignment. + /// + /// This operator returns \c void instead of volatile + /// complex& . See Kokkos Issue #177 for the + /// explanation. In practice, this means that you should not chain + /// assignments with volatile lvalues. + KOKKOS_INLINE_FUNCTION void operator=( + const complex& src) volatile noexcept { + re_ = src.re_; + im_ = src.im_; + // We deliberately do not return anything here. See explanation + // in public documentation above. } - KOKKOS_INLINE_FUNCTION - bool - operator == (const std::complex& src) { - return (re_ == src.real()) && (im_ == src.imag()); + //! Assignment operator, volatile LHS and volatile RHS + // TODO Should this return void like the other volatile assignment operators? + KOKKOS_INLINE_FUNCTION volatile complex& operator=( + const volatile complex& src) volatile noexcept { + re_ = src.re_; + im_ = src.im_; + return *this; } - template - KOKKOS_INLINE_FUNCTION - bool - operator == (const InputRealType src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + //! Assignment operator, volatile RHS and non-volatile LHS + KOKKOS_INLINE_FUNCTION complex& operator=( + const volatile complex& src) noexcept { + re_ = src.re_; + im_ = src.im_; + return *this; + } + + // Mirroring the behavior of the assignment operators from complex RHS in the + // RealType RHS versions. - return (re_ == static_cast(src)) && (im_ == RealType(0)); + //! Assignment operator (from a volatile real number). + KOKKOS_INLINE_FUNCTION void operator=(const volatile RealType& val) noexcept { + re_ = val; + im_ = RealType(0); + // We deliberately do not return anything here. See explanation + // in public documentation above. } - template - KOKKOS_INLINE_FUNCTION - bool - operator != (const complex& src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + //! Assignment operator volatile LHS and non-volatile RHS + KOKKOS_INLINE_FUNCTION complex& operator=( + const RealType& val) volatile noexcept { + re_ = val; + im_ = RealType(0); + return *this; + } - return (re_ != static_cast(src.re_)) || (im_ != static_cast(src.im_)); + //! Assignment operator volatile LHS and volatile RHS + // TODO Should this return void like the other volatile assignment operators? + KOKKOS_INLINE_FUNCTION complex& operator=( + const volatile RealType& val) volatile noexcept { + re_ = val; + im_ = RealType(0); + return *this; } + //! The imaginary part of this complex number (volatile overload). KOKKOS_INLINE_FUNCTION - bool - operator != (const std::complex& src) { - return (re_ != src.real()) || (im_ != src.imag()); - } + volatile RealType& imag() volatile noexcept { return im_; } + + //! The real part of this complex number (volatile overload). + KOKKOS_INLINE_FUNCTION + volatile RealType& real() volatile noexcept { return re_; } + + //! The imaginary part of this complex number (volatile overload). + KOKKOS_INLINE_FUNCTION + RealType imag() const volatile noexcept { return im_; } - template + //! The real part of this complex number (volatile overload). KOKKOS_INLINE_FUNCTION - bool - operator != (const InputRealType src) { - static_assert(std::is_convertible::value, - "InputRealType must be convertible to RealType"); + RealType real() const volatile noexcept { return re_; } + + KOKKOS_INLINE_FUNCTION void operator+=( + const volatile complex& src) volatile noexcept { + re_ += src.re_; + im_ += src.im_; + } + + KOKKOS_INLINE_FUNCTION void operator+=( + const volatile RealType& src) volatile noexcept { + re_ += src; + } + + KOKKOS_INLINE_FUNCTION void operator*=( + const volatile complex& src) volatile noexcept { + const RealType realPart = re_ * src.re_ - im_ * src.im_; + const RealType imagPart = re_ * src.im_ + im_ * src.re_; - return (re_ != static_cast(src)) || (im_ != RealType(0)); + re_ = realPart; + im_ = imagPart; } - + + KOKKOS_INLINE_FUNCTION void operator*=( + const volatile RealType& src) volatile noexcept { + re_ *= src; + im_ *= src; + } + + // TODO DSH 2019-10-7 why are there no volatile /= and friends? }; +//============================================================================== +// {{{1 + +// Note that this is not the same behavior as std::complex, which doesn't allow +// implicit conversions, but since this is the way we had it before, we have +// to do it this way now. + +//! Binary == operator for complex complex. +template +KOKKOS_INLINE_FUNCTION bool operator==(complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y.real()) && + common_type(x.imag()) == common_type(y.imag()); +} + +// TODO (here and elsewhere) decide if we should convert to a Kokkos::complex +// and do the comparison in a device-marked function +//! Binary == operator for std::complex complex. +template +inline bool operator==(std::complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y.real()) && + common_type(x.imag()) == common_type(y.imag()); +} + +//! Binary == operator for complex std::complex. +template +inline bool operator==(complex const& x, + std::complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y.real()) && + common_type(x.imag()) == common_type(y.imag()); +} + +//! Binary == operator for complex real. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator==(complex const& x, + RealType2 const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) == common_type(y) && + common_type(x.imag()) == common_type(0); +} + +//! Binary == operator for real complex. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator==(RealType1 const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x) == common_type(y.real()) && + common_type(0) == common_type(y.imag()); +} + +//! Binary != operator for complex complex. +template +KOKKOS_INLINE_FUNCTION bool operator!=(complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y.real()) || + common_type(x.imag()) != common_type(y.imag()); +} + +//! Binary != operator for std::complex complex. +template +inline bool operator!=(std::complex const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y.real()) || + common_type(x.imag()) != common_type(y.imag()); +} + +//! Binary != operator for complex std::complex. +template +inline bool operator!=(complex const& x, + std::complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y.real()) || + common_type(x.imag()) != common_type(y.imag()); +} + +//! Binary != operator for complex real. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator!=(complex const& x, + RealType2 const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x.real()) != common_type(y) || + common_type(x.imag()) != common_type(0); +} + +//! Binary != operator for real complex. +template < + class RealType1, class RealType2, + // Constraints to avoid participation in oparator==() for every possible RHS + typename std::enable_if::value, + int>::type = 0> +KOKKOS_INLINE_FUNCTION bool operator!=(RealType1 const& x, + complex const& y) noexcept { + using common_type = typename std::common_type::type; + return common_type(x) != common_type(y.real()) || + common_type(0) != common_type(y.imag()); +} + +// end Equality and inequality }}}1 +//============================================================================== //! Binary + operator for complex complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator + (const complex& x, const complex& y) { - return complex::type > (x.real () + y.real (), x.imag () + y.imag ()); + complex::type> + operator+(const complex& x, + const complex& y) noexcept { + return complex::type>( + x.real() + y.real(), x.imag() + y.imag()); } //! Binary + operator for complex scalar. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator + (const complex& x, const RealType2& y) { - return complex::type> (x.real () + y , x.imag ()); + complex::type> + operator+(const complex& x, const RealType2& y) noexcept { + return complex::type>( + x.real() + y, x.imag()); } //! Binary + operator for scalar complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator + (const RealType1& x, const complex& y) { - return complex::type> (x + y.real (), y.imag ()); + complex::type> + operator+(const RealType1& x, const complex& y) noexcept { + return complex::type>( + x + y.real(), y.imag()); } //! Unary + operator for complex. -template -KOKKOS_INLINE_FUNCTION -complex -operator + (const complex& x) { - return x; +template +KOKKOS_INLINE_FUNCTION complex operator+( + const complex& x) noexcept { + return complex{+x.real(), +x.imag()}; } //! Binary - operator for complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator - (const complex& x, const complex& y) { - return complex::type> (x.real () - y.real (), x.imag () - y.imag ()); + complex::type> + operator-(const complex& x, + const complex& y) noexcept { + return complex::type>( + x.real() - y.real(), x.imag() - y.imag()); } //! Binary - operator for complex scalar. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator - (const complex& x, const RealType2& y) { - return complex::type> (x.real () - y , x.imag ()); + complex::type> + operator-(const complex& x, const RealType2& y) noexcept { + return complex::type>( + x.real() - y, x.imag()); } //! Binary - operator for scalar complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator - (const RealType1& x, const complex& y) { - return complex::type> (x - y.real (), - y.imag ()); + complex::type> + operator-(const RealType1& x, const complex& y) noexcept { + return complex::type>( + x - y.real(), -y.imag()); } //! Unary - operator for complex. -template -KOKKOS_INLINE_FUNCTION -complex -operator - (const complex& x) { - return complex (-x.real (), -x.imag ()); +template +KOKKOS_INLINE_FUNCTION complex operator-( + const complex& x) noexcept { + return complex(-x.real(), -x.imag()); } //! Binary * operator for complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator * (const complex& x, const complex& y) { - return complex::type> (x.real () * y.real () - x.imag () * y.imag (), - x.real () * y.imag () + x.imag () * y.real ()); + complex::type> + operator*(const complex& x, + const complex& y) noexcept { + return complex::type>( + x.real() * y.real() - x.imag() * y.imag(), + x.real() * y.imag() + x.imag() * y.real()); } /// \brief Binary * operator for std::complex and complex. /// -/// This function exists because GCC 4.7.2 (and perhaps other -/// compilers) are not able to deduce that they can multiply -/// std::complex by Kokkos::complex, by first converting std::complex -/// to Kokkos::complex. +/// This needs to exist because template parameters can't be deduced when +/// conversions occur. We could probably fix this using hidden friends patterns /// /// This function cannot be called in a CUDA device function, because /// std::complex's methods and nonmember functions are not marked as /// CUDA device functions. -template -inline -complex::type> -operator * (const std::complex& x, const complex& y) { - return complex::type> (x.real () * y.real () - x.imag () * y.imag (), - x.real () * y.imag () + x.imag () * y.real ()); +template +inline complex::type> operator*( + const std::complex& x, const complex& y) { + return complex::type>( + x.real() * y.real() - x.imag() * y.imag(), + x.real() * y.imag() + x.imag() * y.real()); } /// \brief Binary * operator for RealType times complex. /// /// This function exists because the compiler doesn't know that /// RealType and complex commute with respect to operator*. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator * (const RealType1& x, const complex& y) { - return complex::type> (x * y.real (), x * y.imag ()); + complex::type> + operator*(const RealType1& x, const complex& y) noexcept { + return complex::type>( + x * y.real(), x * y.imag()); } /// \brief Binary * operator for RealType times complex. /// /// This function exists because the compiler doesn't know that /// RealType and complex commute with respect to operator*. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator * (const complex& y, const RealType2& x) { - return complex::type> (x * y.real (), x * y.imag ()); + complex::type> + operator*(const complex& y, const RealType2& x) noexcept { + return complex::type>( + x * y.real(), x * y.imag()); } //! Imaginary part of a complex number. -template -KOKKOS_INLINE_FUNCTION -RealType imag (const complex& x) { - return x.imag (); +template +KOKKOS_INLINE_FUNCTION RealType imag(const complex& x) noexcept { + return x.imag(); } //! Real part of a complex number. -template -KOKKOS_INLINE_FUNCTION -RealType real (const complex& x) { - return x.real (); +template +KOKKOS_INLINE_FUNCTION RealType real(const complex& x) noexcept { + return x.real(); } //! Absolute value (magnitude) of a complex number. -template -KOKKOS_INLINE_FUNCTION -RealType abs (const complex& x) { +template +KOKKOS_INLINE_FUNCTION RealType abs(const complex& x) { #ifndef __CUDA_ARCH__ using std::hypot; #endif - return hypot(x.real(),x.imag()); + return hypot(x.real(), x.imag()); } //! Power of a complex number -template -KOKKOS_INLINE_FUNCTION -Kokkos::complex pow (const complex& x, const RealType& e) { - RealType r = abs(x); - RealType phi = std::atan(x.imag()/x.real()); - return std::pow(r,e) * Kokkos::complex(std::cos(phi*e),std::sin(phi*e)); +template +KOKKOS_INLINE_FUNCTION Kokkos::complex pow(const complex& x, + const RealType& e) { + RealType r = abs(x); + RealType phi = std::atan(x.imag() / x.real()); + return std::pow(r, e) * + Kokkos::complex(std::cos(phi * e), std::sin(phi * e)); } //! Square root of a complex number. -template -KOKKOS_INLINE_FUNCTION -Kokkos::complex sqrt (const complex& x) { - RealType r = abs(x); - RealType phi = std::atan(x.imag()/x.real()); - return std::sqrt(r) * Kokkos::complex(std::cos(phi*0.5),std::sin(phi*0.5)); +template +KOKKOS_INLINE_FUNCTION Kokkos::complex sqrt( + const complex& x) { + RealType r = abs(x); + RealType phi = std::atan(x.imag() / x.real()); + return std::sqrt(r) * + Kokkos::complex(std::cos(phi * 0.5), std::sin(phi * 0.5)); } //! Conjugate of a complex number. -template -KOKKOS_INLINE_FUNCTION -complex conj (const complex& x) { - return complex (real (x), -imag (x)); +template +KOKKOS_INLINE_FUNCTION complex conj( + const complex& x) noexcept { + return complex(real(x), -imag(x)); } //! Exponential of a complex number. -template -KOKKOS_INLINE_FUNCTION -complex exp (const complex& x) { - return std::exp(x.real()) * complex (std::cos (x.imag()), std::sin(x.imag())); +template +KOKKOS_INLINE_FUNCTION complex exp(const complex& x) { + return std::exp(x.real()) * + complex(std::cos(x.imag()), std::sin(x.imag())); } /// This function cannot be called in a CUDA device function, /// because std::complex's methods and nonmember functions are not /// marked as CUDA device functions. -template -inline -complex -exp (const std::complex& c) { - return complex( std::exp( c.real() )*std::cos( c.imag() ), std::exp( c.real() )*std::sin( c.imag() ) ); +template +inline complex exp(const std::complex& c) { + return complex(std::exp(c.real()) * std::cos(c.imag()), + std::exp(c.real()) * std::sin(c.imag())); } //! Binary operator / for complex and real numbers -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator / (const complex& x, const RealType2& y) { - return complex::type> (real (x) / y, imag (x) / y); + complex::type> + operator/(const complex& x, + const RealType2& y) noexcept(noexcept(RealType1{} / + RealType2{})) { + return complex::type>( + real(x) / y, imag(x) / y); } //! Binary operator / for complex. -template +template KOKKOS_INLINE_FUNCTION -complex::type> -operator / (const complex& x, const complex& y) { + complex::type> + operator/(const complex& x, + const complex& y) noexcept(noexcept(RealType1{} / + RealType2{})) { // Scale (by the "1-norm" of y) to avoid unwarranted overflow. // If the real part is +/-Inf and the imaginary part is -/+Inf, // this won't change the result. - typedef typename std::common_type::type common_real_type; - const common_real_type s = std::fabs (real (y)) + std::fabs (imag (y)); + typedef + typename std::common_type::type common_real_type; + const common_real_type s = std::fabs(real(y)) + std::fabs(imag(y)); // If s is 0, then y is zero, so x/y == real(x)/0 + i*imag(x)/0. // In that case, the relation x/y == (x/s) / (y/s) doesn't hold, // because y/s is NaN. if (s == 0.0) { - return complex (real (x) / s, imag (x) / s); - } - else { - const complex x_scaled (real (x) / s, imag (x) / s); - const complex y_conj_scaled (real (y) / s, -imag (y) / s); - const RealType1 y_scaled_abs = real (y_conj_scaled) * real (y_conj_scaled) + - imag (y_conj_scaled) * imag (y_conj_scaled); // abs(y) == abs(conj(y)) + return complex(real(x) / s, imag(x) / s); + } else { + const complex x_scaled(real(x) / s, imag(x) / s); + const complex y_conj_scaled(real(y) / s, -imag(y) / s); + const RealType1 y_scaled_abs = + real(y_conj_scaled) * real(y_conj_scaled) + + imag(y_conj_scaled) * imag(y_conj_scaled); // abs(y) == abs(conj(y)) complex result = x_scaled * y_conj_scaled; result /= y_scaled_abs; return result; @@ -716,119 +742,43 @@ operator / (const complex& x, const complex& y) { } //! Binary operator / for complex and real numbers -template -KOKKOS_INLINE_FUNCTION -complex::type> -operator / (const RealType1& x, const complex& y) { - return complex::type> (x)/y; -} - -//! Equality operator for two complex numbers. -template -KOKKOS_INLINE_FUNCTION -bool -operator == (const complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) == static_cast(real (y)) && - static_cast(imag (x)) == static_cast(imag (y)) ); -} - -/// \brief Equality operator for std::complex and Kokkos::complex. -/// -/// This cannot be a device function, since std::real is not. -/// Otherwise, CUDA builds will give compiler warnings ("warning: -/// calling a constexpr __host__ function("real") from a __host__ -/// __device__ function("operator==") is not allowed"). -template -inline -bool -operator == (const std::complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(std::real (x)) == static_cast(real (y)) && - static_cast(std::imag (x)) == static_cast(imag (y)) ); -} - -//! Equality operator for complex and real number. -template -KOKKOS_INLINE_FUNCTION -bool -operator == (const complex& x, const RealType2& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) == static_cast(y) && - static_cast(imag (x)) == static_cast(0.0) ); -} - -//! Equality operator for real and complex number. -template -KOKKOS_INLINE_FUNCTION -bool -operator == (const RealType1& x, const complex& y) { - return y == x; -} - -//! Inequality operator for two complex numbers. -template +template KOKKOS_INLINE_FUNCTION -bool -operator != (const complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) != static_cast(real (y)) || - static_cast(imag (x)) != static_cast(imag (y)) ); -} - -//! Inequality operator for std::complex and Kokkos::complex. -template -inline -bool -operator != (const std::complex& x, const complex& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(std::real (x)) != static_cast(real (y)) || - static_cast(std::imag (x)) != static_cast(imag (y)) ); + complex::type> + operator/(const RealType1& x, + const complex& y) noexcept(noexcept(RealType1{} / + RealType2{})) { + return complex::type>(x) / y; } -//! Inequality operator for complex and real number. -template -KOKKOS_INLINE_FUNCTION -bool -operator != (const complex& x, const RealType2& y) { - typedef typename std::common_type::type common_real_type; - return ( static_cast(real (x)) != static_cast(y) || - static_cast(imag (x)) != static_cast(0.0) ); -} - -//! Inequality operator for real and complex number. -template -KOKKOS_INLINE_FUNCTION -bool -operator != (const RealType1& x, const complex& y) { - return y != x; -} - -template -std::ostream& operator << (std::ostream& os, const complex& x) { - const std::complex x_std (Kokkos::real (x), Kokkos::imag (x)); +template +std::ostream& operator<<(std::ostream& os, const complex& x) { + const std::complex x_std(Kokkos::real(x), Kokkos::imag(x)); os << x_std; return os; } -template -std::ostream& operator >> (std::ostream& os, complex& x) { +template +std::istream& operator>>(std::istream& is, complex& x) { std::complex x_std; - os >> x_std; - x = x_std; // only assigns on success of above - return os; + is >> x_std; + x = x_std; // only assigns on success of above + return is; } - -template +template struct reduction_identity > { typedef reduction_identity t_red_ident; - KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex sum() - {return Kokkos::complex(t_red_ident::sum(),t_red_ident::sum());} - KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex prod() - {return Kokkos::complex(t_red_ident::prod(),t_red_ident::sum());} + KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex + sum() noexcept { + return Kokkos::complex(t_red_ident::sum(), t_red_ident::sum()); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static Kokkos::complex + prod() noexcept { + return Kokkos::complex(t_red_ident::prod(), t_red_ident::sum()); + } }; -} // namespace Kokkos +} // namespace Kokkos -#endif // KOKKOS_COMPLEX_HPP +#endif // KOKKOS_COMPLEX_HPP diff --git a/lib/kokkos/core/src/Kokkos_Concepts.hpp b/lib/kokkos/core/src/Kokkos_Concepts.hpp index ca2e8b4eb6..abfa88e1d2 100644 --- a/lib/kokkos/core/src/Kokkos_Concepts.hpp +++ b/lib/kokkos/core/src/Kokkos_Concepts.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -54,245 +55,264 @@ namespace Kokkos { -//Schedules for Execution Policies +// Schedules for Execution Policies struct Static {}; struct Dynamic {}; -//Schedule Wrapper Type -template -struct Schedule -{ - static_assert( std::is_same::value - || std::is_same::value - , "Kokkos: Invalid Schedule<> type." - ); - using schedule_type = Schedule ; - using type = T; +// Schedule Wrapper Type +template +struct Schedule { + static_assert(std::is_same::value || + std::is_same::value, + "Kokkos: Invalid Schedule<> type."); + using schedule_type = Schedule; + using type = T; }; -//Specify Iteration Index Type -template -struct IndexType -{ - static_assert(std::is_integral::value,"Kokkos: Invalid IndexType<>."); - using index_type = IndexType ; - using type = T; +// Specify Iteration Index Type +template +struct IndexType { + static_assert(std::is_integral::value, "Kokkos: Invalid IndexType<>."); + using index_type = IndexType; + using type = T; }; namespace Experimental { - struct WorkItemProperty { - template - struct ImplWorkItemProperty { - static const unsigned value = Property; - using work_item_property = ImplWorkItemProperty; - }; - - constexpr static const ImplWorkItemProperty<0> None = ImplWorkItemProperty<0>(); - constexpr static const ImplWorkItemProperty<1> HintLightWeight = ImplWorkItemProperty<1>(); - constexpr static const ImplWorkItemProperty<2> HintHeavyWeight = ImplWorkItemProperty<2>(); - constexpr static const ImplWorkItemProperty<4> HintRegular = ImplWorkItemProperty<4>(); - constexpr static const ImplWorkItemProperty<8> HintIrregular = ImplWorkItemProperty<8>(); - typedef ImplWorkItemProperty<0> None_t; - typedef ImplWorkItemProperty<1> HintLightWeight_t; - typedef ImplWorkItemProperty<2> HintHeavyWeight_t; - typedef ImplWorkItemProperty<4> HintRegular_t; - typedef ImplWorkItemProperty<8> HintIrregular_t; +struct WorkItemProperty { + template + struct ImplWorkItemProperty { + static const unsigned value = Property; + using work_item_property = ImplWorkItemProperty; }; -template -inline constexpr WorkItemProperty::ImplWorkItemProperty operator | - (WorkItemProperty::ImplWorkItemProperty, WorkItemProperty::ImplWorkItemProperty) { - return WorkItemProperty::ImplWorkItemProperty(); -} + constexpr static const ImplWorkItemProperty<0> None = + ImplWorkItemProperty<0>(); + constexpr static const ImplWorkItemProperty<1> HintLightWeight = + ImplWorkItemProperty<1>(); + constexpr static const ImplWorkItemProperty<2> HintHeavyWeight = + ImplWorkItemProperty<2>(); + constexpr static const ImplWorkItemProperty<4> HintRegular = + ImplWorkItemProperty<4>(); + constexpr static const ImplWorkItemProperty<8> HintIrregular = + ImplWorkItemProperty<8>(); + typedef ImplWorkItemProperty<0> None_t; + typedef ImplWorkItemProperty<1> HintLightWeight_t; + typedef ImplWorkItemProperty<2> HintHeavyWeight_t; + typedef ImplWorkItemProperty<4> HintRegular_t; + typedef ImplWorkItemProperty<8> HintIrregular_t; +}; -template -inline constexpr WorkItemProperty::ImplWorkItemProperty operator & - (WorkItemProperty::ImplWorkItemProperty, WorkItemProperty::ImplWorkItemProperty) { - return WorkItemProperty::ImplWorkItemProperty(); +template +inline constexpr WorkItemProperty::ImplWorkItemProperty operator|( + WorkItemProperty::ImplWorkItemProperty, + WorkItemProperty::ImplWorkItemProperty) { + return WorkItemProperty::ImplWorkItemProperty(); } -template -inline constexpr bool operator == (WorkItemProperty::ImplWorkItemProperty, WorkItemProperty::ImplWorkItemProperty) { - return pv1 == pv2; +template +inline constexpr WorkItemProperty::ImplWorkItemProperty operator&( + WorkItemProperty::ImplWorkItemProperty, + WorkItemProperty::ImplWorkItemProperty) { + return WorkItemProperty::ImplWorkItemProperty(); } +template +inline constexpr bool operator==(WorkItemProperty::ImplWorkItemProperty, + WorkItemProperty::ImplWorkItemProperty) { + return pv1 == pv2; } +} // namespace Experimental + /**\brief Specify Launch Bounds for CUDA execution. * * If no launch bounds specified then do not set launch bounds. */ -template< unsigned int maxT = 0 /* Max threads per block */ - , unsigned int minB = 0 /* Min blocks per SM */ - > -struct LaunchBounds -{ +template +struct LaunchBounds { using launch_bounds = LaunchBounds; - using type = LaunchBounds; - static unsigned int constexpr maxTperB {maxT}; - static unsigned int constexpr minBperSM {minB}; + using type = LaunchBounds; + static unsigned int constexpr maxTperB{maxT}; + static unsigned int constexpr minBperSM{minB}; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Kokkos { -#define KOKKOS_IMPL_IS_CONCEPT( CONCEPT ) \ - template< typename T > struct is_ ## CONCEPT { \ - private: \ - template< typename , typename = std::true_type > struct have : std::false_type {}; \ - template< typename U > struct have::type, \ - typename std::remove_cv::type \ - >::type> : std::true_type {}; \ - template< typename U > struct have::type, \ - typename std::remove_cv::type \ - >::type> : std::true_type {}; \ - public: \ - enum { value = is_ ## CONCEPT::template have::value }; \ +#define KOKKOS_IMPL_IS_CONCEPT(CONCEPT) \ + template \ + struct is_##CONCEPT { \ + private: \ + template \ + struct have : std::false_type {}; \ + template \ + struct have::type, \ + typename std::remove_cv::type>::type> \ + : std::true_type {}; \ + template \ + struct have::type, \ + typename std::remove_cv::type>::type> \ + : std::true_type {}; \ + \ + public: \ + enum { value = is_##CONCEPT::template have::value }; \ }; // Public concept: -KOKKOS_IMPL_IS_CONCEPT( memory_space ) -KOKKOS_IMPL_IS_CONCEPT( memory_traits ) -KOKKOS_IMPL_IS_CONCEPT( execution_space ) -KOKKOS_IMPL_IS_CONCEPT( execution_policy ) -KOKKOS_IMPL_IS_CONCEPT( array_layout ) -KOKKOS_IMPL_IS_CONCEPT( reducer ) +KOKKOS_IMPL_IS_CONCEPT(memory_space) +KOKKOS_IMPL_IS_CONCEPT(memory_traits) +KOKKOS_IMPL_IS_CONCEPT(execution_space) +KOKKOS_IMPL_IS_CONCEPT(execution_policy) +KOKKOS_IMPL_IS_CONCEPT(array_layout) +KOKKOS_IMPL_IS_CONCEPT(reducer) namespace Experimental { -KOKKOS_IMPL_IS_CONCEPT( work_item_property ) +KOKKOS_IMPL_IS_CONCEPT(work_item_property) } namespace Impl { // For backward compatibility: -using Kokkos::is_memory_space ; -using Kokkos::is_memory_traits ; -using Kokkos::is_execution_space ; -using Kokkos::is_execution_policy ; -using Kokkos::is_array_layout ; +using Kokkos::is_array_layout; +using Kokkos::is_execution_policy; +using Kokkos::is_execution_space; +using Kokkos::is_memory_space; +using Kokkos::is_memory_traits; // Implementation concept: -KOKKOS_IMPL_IS_CONCEPT( iteration_pattern ) -KOKKOS_IMPL_IS_CONCEPT( schedule_type ) -KOKKOS_IMPL_IS_CONCEPT( index_type ) -KOKKOS_IMPL_IS_CONCEPT( launch_bounds ) -KOKKOS_IMPL_IS_CONCEPT( thread_team_member ) -KOKKOS_IMPL_IS_CONCEPT( host_thread_team_member ) +KOKKOS_IMPL_IS_CONCEPT(iteration_pattern) +KOKKOS_IMPL_IS_CONCEPT(schedule_type) +KOKKOS_IMPL_IS_CONCEPT(index_type) +KOKKOS_IMPL_IS_CONCEPT(launch_bounds) +KOKKOS_IMPL_IS_CONCEPT(thread_team_member) +KOKKOS_IMPL_IS_CONCEPT(host_thread_team_member) -} +} // namespace Impl #undef KOKKOS_IMPL_IS_CONCEPT -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -template< class ExecutionSpace , class MemorySpace > +template struct Device { - static_assert( Kokkos::is_execution_space::value - , "Execution space is not valid" ); - static_assert( Kokkos::is_memory_space::value - , "Memory space is not valid" ); - typedef ExecutionSpace execution_space; - typedef MemorySpace memory_space; - typedef Device device_type; + static_assert(Kokkos::is_execution_space::value, + "Execution space is not valid"); + static_assert(Kokkos::is_memory_space::value, + "Memory space is not valid"); + typedef ExecutionSpace execution_space; + typedef MemorySpace memory_space; + typedef Device device_type; }; - -template< typename T > +template struct is_space { -private: - - template< typename , typename = void > - struct exe : std::false_type { typedef void space ; }; - - template< typename , typename = void > - struct mem : std::false_type { typedef void space ; }; + private: + template + struct exe : std::false_type { + typedef void space; + }; - template< typename , typename = void > - struct dev : std::false_type { typedef void space ; }; + template + struct mem : std::false_type { + typedef void space; + }; - template< typename U > - struct exe::type> - : std::is_same::type - { typedef typename U::execution_space space ; }; + template + struct dev : std::false_type { + typedef void space; + }; - template< typename U > - struct mem::type> - : std::is_same::type - { typedef typename U::memory_space space ; }; + template + struct exe::type> + : std::is_same::type { + typedef typename U::execution_space space; + }; - template< typename U > - struct dev::type> - : std::is_same::type - { typedef typename U::device_type space ; }; + template + struct mem< + U, typename std::conditional::type> + : std::is_same::type { + typedef typename U::memory_space space; + }; - typedef typename is_space::template exe is_exe ; - typedef typename is_space::template mem is_mem ; - typedef typename is_space::template dev is_dev ; + template + struct dev< + U, typename std::conditional::type> + : std::is_same::type { + typedef typename U::device_type space; + }; -public: + typedef typename is_space::template exe is_exe; + typedef typename is_space::template mem is_mem; + typedef typename is_space::template dev is_dev; + public: enum { value = is_exe::value || is_mem::value || is_dev::value }; - typedef typename is_exe::space execution_space ; - typedef typename is_mem::space memory_space ; + typedef typename is_exe::space execution_space; + typedef typename is_mem::space memory_space; // For backward compatibility, deprecated in favor of // Kokkos::Impl::HostMirror::host_mirror_space - typedef typename std::conditional - < std::is_same< memory_space , Kokkos::HostSpace >::value -#if defined( KOKKOS_ENABLE_CUDA ) - || std::is_same< memory_space , Kokkos::CudaUVMSpace >::value - || std::is_same< memory_space , Kokkos::CudaHostPinnedSpace >::value + typedef typename std::conditional< + std::is_same::value +#if defined(KOKKOS_ENABLE_CUDA) + || std::is_same::value || + std::is_same::value #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ - , memory_space - , Kokkos::HostSpace - >::type host_memory_space ; - -#if defined( KOKKOS_ENABLE_CUDA ) - typedef typename std::conditional - < std::is_same< execution_space , Kokkos::Cuda >::value - , Kokkos::DefaultHostExecutionSpace , execution_space - >::type host_execution_space ; + , + memory_space, Kokkos::HostSpace>::type host_memory_space; + +#if defined(KOKKOS_ENABLE_CUDA) + typedef typename std::conditional< + std::is_same::value, + Kokkos::DefaultHostExecutionSpace, execution_space>::type + host_execution_space; +#else +#if defined(KOKKOS_ENABLE_OPENMPTARGET) + typedef typename std::conditional< + std::is_same::value, + Kokkos::DefaultHostExecutionSpace, execution_space>::type + host_execution_space; #else - #if defined( KOKKOS_ENABLE_OPENMPTARGET ) - typedef typename std::conditional - < std::is_same< execution_space , Kokkos::Experimental::OpenMPTarget >::value - , Kokkos::DefaultHostExecutionSpace , execution_space - >::type host_execution_space ; - #else - typedef execution_space host_execution_space ; - #endif + typedef execution_space host_execution_space; +#endif #endif - typedef typename std::conditional - < std::is_same< execution_space , host_execution_space >::value && - std::is_same< memory_space , host_memory_space >::value - , T , Kokkos::Device< host_execution_space , host_memory_space > - >::type host_mirror_space ; + typedef typename std::conditional< + std::is_same::value && + std::is_same::value, + T, Kokkos::Device >::type + host_mirror_space; }; -// For backward compatibility +// For backward compatiblity namespace Impl { -using Kokkos::is_space ; +using Kokkos::is_space; } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -304,12 +324,11 @@ namespace Impl { * The default case can assume accessibility for the same space. * Specializations must be defined for different memory spaces. */ -template< typename DstMemorySpace , typename SrcMemorySpace > +template struct MemorySpaceAccess { - - static_assert( Kokkos::is_memory_space< DstMemorySpace >::value && - Kokkos::is_memory_space< SrcMemorySpace >::value - , "template arguments must be memory spaces" ); + static_assert(Kokkos::is_memory_space::value && + Kokkos::is_memory_space::value, + "template arguments must be memory spaces"); /**\brief Can a View (or pointer) to memory in SrcMemorySpace * be assigned to a View (or pointer) to memory marked DstMemorySpace. @@ -318,7 +337,7 @@ struct MemorySpaceAccess { * 2. All execution spaces that can access DstMemorySpace can also access * SrcMemorySpace. */ - enum { assignable = std::is_same::value }; + enum { assignable = std::is_same::value }; /**\brief For all DstExecSpace::memory_space == DstMemorySpace * DstExecSpace can access SrcMemorySpace. @@ -331,7 +350,8 @@ struct MemorySpaceAccess { enum { deepcopy = assignable }; }; -}} // namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos namespace Kokkos { @@ -354,34 +374,31 @@ namespace Kokkos { * When AccessSpace::memory_space == Kokkos::HostSpace * then space is the View host mirror space. */ -template< typename AccessSpace , typename MemorySpace > +template struct SpaceAccessibility { -private: + private: + static_assert(Kokkos::is_space::value, + "template argument #1 must be a Kokkos space"); - static_assert( Kokkos::is_space< AccessSpace >::value - , "template argument #1 must be a Kokkos space" ); - - static_assert( Kokkos::is_memory_space< MemorySpace >::value - , "template argument #2 must be a Kokkos memory space" ); + static_assert(Kokkos::is_memory_space::value, + "template argument #2 must be a Kokkos memory space"); // The input AccessSpace may be a Device // verify that it is a valid combination of spaces. - static_assert( Kokkos::Impl::MemorySpaceAccess - < typename AccessSpace::execution_space::memory_space - , typename AccessSpace::memory_space - >::accessible - , "template argument #1 is an invalid space" ); - - typedef Kokkos::Impl::MemorySpaceAccess - < typename AccessSpace::execution_space::memory_space , MemorySpace > - exe_access ; + static_assert(Kokkos::Impl::MemorySpaceAccess< + typename AccessSpace::execution_space::memory_space, + typename AccessSpace::memory_space>::accessible, + "template argument #1 is an invalid space"); - typedef Kokkos::Impl::MemorySpaceAccess - < typename AccessSpace::memory_space , MemorySpace > - mem_access ; + typedef Kokkos::Impl::MemorySpaceAccess< + typename AccessSpace::execution_space::memory_space, MemorySpace> + exe_access; -public: + typedef Kokkos::Impl::MemorySpaceAccess + mem_access; + public: /**\brief Can AccessSpace::execution_space access MemorySpace ? * * Default based upon memory space accessibility. @@ -394,8 +411,9 @@ public: * Default based upon memory space accessibility. * Specialization required for other relationships. */ - enum { assignable = - is_memory_space< AccessSpace >::value && mem_access::assignable }; + enum { + assignable = is_memory_space::value && mem_access::assignable + }; /**\brief Can deep copy to AccessSpace::memory_Space from MemorySpace ? */ enum { deepcopy = mem_access::deepcopy }; @@ -404,24 +422,24 @@ public: // to be able to access MemorySpace? // If same memory space or not accessible use the AccessSpace // else construct a device with execution space and memory space. - typedef typename std::conditional - < std::is_same::value || - ! exe_access::accessible - , AccessSpace - , Kokkos::Device< typename AccessSpace::execution_space , MemorySpace > - >::type space ; + typedef typename std::conditional< + std::is_same::value || + !exe_access::accessible, + AccessSpace, + Kokkos::Device >::type + space; }; -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Impl { -using Kokkos::SpaceAccessibility ; // For backward compatibility +using Kokkos::SpaceAccessibility; // For backward compatibility -}} // namespace Kokkos::Impl +} +} // namespace Kokkos //---------------------------------------------------------------------------- -#endif // KOKKOS_CORE_CONCEPTS_HPP - +#endif // KOKKOS_CORE_CONCEPTS_HPP diff --git a/lib/kokkos/core/src/Kokkos_CopyViews.hpp b/lib/kokkos/core/src/Kokkos_CopyViews.hpp index 9210f21ab7..e64b434d02 100644 --- a/lib/kokkos/core/src/Kokkos_CopyViews.hpp +++ b/lib/kokkos/core/src/Kokkos_CopyViews.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -56,1479 +57,1781 @@ namespace Kokkos { namespace Impl { -template -struct ViewFillLayoutSelector { -}; +template +struct ViewFillLayoutSelector {}; -template<> +template <> struct ViewFillLayoutSelector { static const Kokkos::Iterate iterate = Kokkos::Iterate::Left; }; -template<> +template <> struct ViewFillLayoutSelector { static const Kokkos::Iterate iterate = Kokkos::Iterate::Right; }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos -#include +#include namespace Kokkos { namespace Impl { -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&) const; + void operator()(const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&) const; + void operator()(const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType&, const ST&); KOKKOS_INLINE_FUNCTION - void operator() (const iType&, const iType&, const iType&, const iType&, - const iType&, const iType&, const iType&, const iType&) const; + void operator()(const iType&, const iType&, const iType&, const iType&, + const iType&, const iType&, const iType&, const iType&) const; }; -template -struct ViewFill { +template +struct ViewFill { typedef typename ViewType::non_const_value_type ST; ViewFill(const ViewType& a, const ST& val) { - Kokkos::Impl::DeepCopy< typename ViewType::memory_space, Kokkos::HostSpace >( a.data() , &val, sizeof(ST) ); + Kokkos::Impl::DeepCopy( + a.data(), &val, sizeof(ST)); } }; - -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::RangePolicy> policy_type; + typedef Kokkos::RangePolicy> policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewFill-1D",policy_type(0,a.extent(0)),*this); + Kokkos::parallel_for("Kokkos::ViewFill-1D", policy_type(0, a.extent(0)), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i) const { - a(i) = val; - }; + void operator()(const iType& i) const { a(i) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<2,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<2, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-2D", - policy_type({0,0},{a.extent(0),a.extent(1)}),*this); + policy_type({0, 0}, {a.extent(0), a.extent(1)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1) const { - a(i0,i1) = val; - }; + void operator()(const iType& i0, const iType& i1) const { a(i0, i1) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<3,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<3, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewFill-3D", - policy_type({0,0,0},{a.extent(0),a.extent(1),a.extent(2)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewFill-3D", + policy_type({0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2)}), *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2) const { - a(i0,i1,i2) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2) const { + a(i0, i1, i2) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<4,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<4, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-4D", - policy_type({0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3)}),*this); + policy_type({0, 0, 0, 0}, {a.extent(0), a.extent(1), + a.extent(2), a.extent(3)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, const iType& i3) const { - a(i0,i1,i2,i3) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3) const { + a(i0, i1, i2, i3) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<5,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<5, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewFill-5D", - policy_type({0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3),a.extent(4)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewFill-5D", + policy_type({0, 0, 0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, const iType& i3, const iType& i4) const { - a(i0,i1,i2,i3,i4) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4) const { + a(i0, i1, i2, i3, i4) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<6,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<6, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-6D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3),a.extent(4),a.extent(5)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4), a.extent(5)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, const iType& i3, const iType& i4, const iType& i5) const { - a(i0,i1,i2,i3,i4,i5) = val; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5) const { + a(i0, i1, i2, i3, i4, i5) = val; }; }; -template -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<6,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<6, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-7D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2),a.extent(3), - a.extent(5),a.extent(6)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(5), a.extent(6)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i4, const iType& i5, const iType& i6) const { - for(iType i2=0; i2 -struct ViewFill { +template +struct ViewFill { ViewType a; typename ViewType::const_value_type val; - typedef Kokkos::Rank<6,ViewFillLayoutSelector::iterate,ViewFillLayoutSelector::iterate> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; + typedef Kokkos::Rank<6, ViewFillLayoutSelector::iterate, + ViewFillLayoutSelector::iterate> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; - ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_):a(a_),val(val_) { + ViewFill(const ViewType& a_, typename ViewType::const_value_type& val_) + : a(a_), val(val_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewFill-8D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(3), - a.extent(5),a.extent(6),a.extent(7)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(3), + a.extent(5), a.extent(6), a.extent(7)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i5, const iType& i6, const iType& i7) const { - for(iType i2=0; i2 -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0) const; + void operator()(const iType& i0) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1) const; + void operator()(const iType& i0, const iType& i1) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2) const; + void operator()(const iType& i0, const iType& i1, const iType& i2) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4,const iType& i5) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4,const iType& i5,const iType& i6) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5, + const iType& i6) const; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; ViewCopy(const ViewTypeA&, const ViewTypeB&); KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0,const iType& i1,const iType& i2,const iType& i3, - const iType& i4,const iType& i5,const iType& i6,const iType& i7) const; + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5, + const iType& i6, const iType& i7) const; }; - - -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - typedef Kokkos::RangePolicy> policy_type; + typedef Kokkos::RangePolicy> policy_type; - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewCopy-1D", - policy_type(0,a.extent(0)),*this); + Kokkos::parallel_for("Kokkos::ViewCopy-1D", policy_type(0, a.extent(0)), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0) const { - a(i0) = b(i0); - }; + void operator()(const iType& i0) const { a(i0) = b(i0); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<2,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<2, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-2D", - policy_type({0,0},{a.extent(0),a.extent(1)}),*this); + policy_type({0, 0}, {a.extent(0), a.extent(1)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1) const { - a(i0,i1) = b(i0,i1); + void operator()(const iType& i0, const iType& i1) const { + a(i0, i1) = b(i0, i1); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<3,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<3, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewCopy-3D", - policy_type({0,0,0},{a.extent(0),a.extent(1),a.extent(2)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewCopy-3D", + policy_type({0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2)}), *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2) const { - a(i0,i1,i2) = b(i0,i1,i2); + void operator()(const iType& i0, const iType& i1, const iType& i2) const { + a(i0, i1, i2) = b(i0, i1, i2); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<4,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<4, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-4D", - policy_type({0,0,0,0},{a.extent(0),a.extent(1),a.extent(2), - a.extent(3)}),*this); + policy_type({0, 0, 0, 0}, {a.extent(0), a.extent(1), + a.extent(2), a.extent(3)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, - const iType& i3) const { - a(i0,i1,i2,i3) = b(i0,i1,i2,i3); + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3) const { + a(i0, i1, i2, i3) = b(i0, i1, i2, i3); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<5,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<5, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); - Kokkos::parallel_for("Kokkos::ViewCopy-5D", - policy_type({0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2), - a.extent(3),a.extent(4)}),*this); + Kokkos::parallel_for( + "Kokkos::ViewCopy-5D", + policy_type({0, 0, 0, 0, 0}, {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, - const iType& i3, const iType& i4) const { - a(i0,i1,i2,i3,i4) = b(i0,i1,i2,i3,i4); + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4) const { + a(i0, i1, i2, i3, i4) = b(i0, i1, i2, i3, i4); }; }; -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<6,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<6, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-6D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(2), - a.extent(3),a.extent(4),a.extent(5)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(2), + a.extent(3), a.extent(4), a.extent(5)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i2, - const iType& i3, const iType& i4, const iType& i5) const { - a(i0,i1,i2,i3,i4,i5) = b(i0,i1,i2,i3,i4,i5); + void operator()(const iType& i0, const iType& i1, const iType& i2, + const iType& i3, const iType& i4, const iType& i5) const { + a(i0, i1, i2, i3, i4, i5) = b(i0, i1, i2, i3, i4, i5); }; }; - -template -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<6,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<6, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-7D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(3), - a.extent(4),a.extent(5),a.extent(6)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(3), + a.extent(4), a.extent(5), a.extent(6)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i4, const iType& i5, const iType& i6) const { - for(iType i2=0; i2 -struct ViewCopy { +template +struct ViewCopy { ViewTypeA a; ViewTypeB b; - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::layout_iterate_type_selector::inner_iteration_pattern; - typedef Kokkos::Rank<6,outer_iteration_pattern,inner_iteration_pattern> iterate_type; - typedef Kokkos::MDRangePolicy> policy_type; - - ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_):a(a_),b(b_) { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::layout_iterate_type_selector::outer_iteration_pattern; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::layout_iterate_type_selector::inner_iteration_pattern; + typedef Kokkos::Rank<6, outer_iteration_pattern, inner_iteration_pattern> + iterate_type; + typedef Kokkos::MDRangePolicy> + policy_type; + + ViewCopy(const ViewTypeA& a_, const ViewTypeB& b_) : a(a_), b(b_) { ExecSpace().fence(); Kokkos::parallel_for("Kokkos::ViewCopy-8D", - policy_type({0,0,0,0,0,0},{a.extent(0),a.extent(1),a.extent(3), - a.extent(5),a.extent(6),a.extent(7)}),*this); + policy_type({0, 0, 0, 0, 0, 0}, + {a.extent(0), a.extent(1), a.extent(3), + a.extent(5), a.extent(6), a.extent(7)}), + *this); ExecSpace().fence(); } KOKKOS_INLINE_FUNCTION - void operator() (const iType& i0, const iType& i1, const iType& i3, - const iType& i5, const iType& i6, const iType& i7) const { - for(iType i2=0; i2 +#include namespace Kokkos { namespace Impl { -template +template void view_copy(const DstType& dst, const SrcType& src) { typedef typename DstType::execution_space dst_execution_space; typedef typename SrcType::execution_space src_execution_space; typedef typename DstType::memory_space dst_memory_space; typedef typename SrcType::memory_space src_memory_space; - enum { DstExecCanAccessSrc = - Kokkos::Impl::SpaceAccessibility< dst_execution_space , src_memory_space >::accessible }; + enum { + DstExecCanAccessSrc = + Kokkos::Impl::SpaceAccessibility::accessible + }; - enum { SrcExecCanAccessDst = - Kokkos::Impl::SpaceAccessibility< src_execution_space , dst_memory_space >::accessible }; + enum { + SrcExecCanAccessDst = + Kokkos::Impl::SpaceAccessibility::accessible + }; - if( ! DstExecCanAccessSrc && ! SrcExecCanAccessDst) { - std::string message("Error: Kokkos::deep_copy with no available copy mechanism: "); - message += src.label(); message += " to "; + if (!DstExecCanAccessSrc && !SrcExecCanAccessDst) { + std::string message( + "Error: Kokkos::deep_copy with no available copy mechanism: "); + message += src.label(); + message += " to "; message += dst.label(); Kokkos::Impl::throw_runtime_exception(message); } // Figure out iteration order in case we need it - int64_t strides[DstType::Rank+1]; + int64_t strides[DstType::Rank + 1]; dst.stride(strides); Kokkos::Iterate iterate; - if ( Kokkos::is_layouttiled::value ) { - iterate = Kokkos::layout_iterate_type_selector::outer_iteration_pattern; - } else if ( std::is_same::value ) { + if (Kokkos::is_layouttiled::value) { + iterate = Kokkos::layout_iterate_type_selector< + typename DstType::array_layout>::outer_iteration_pattern; + } else if (std::is_same::value) { iterate = Kokkos::Iterate::Right; - } else if ( std::is_same::value ) { + } else if (std::is_same::value) { iterate = Kokkos::Iterate::Left; - } else if ( std::is_same::value ) { - if( strides[0] > strides[DstType::Rank-1] ) + } else if (std::is_same::value) { + if (strides[0] > strides[DstType::Rank - 1]) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } else { - if( std::is_same::value ) + if (std::is_same::value) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } - if( (dst.span() >= size_t(std::numeric_limits::max())) || - (src.span() >= size_t(std::numeric_limits::max())) ){ - if(DstExecCanAccessSrc) { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, dst_execution_space, - DstType::Rank, int64_t >( dst , src ); + if ((dst.span() >= size_t(std::numeric_limits::max())) || + (src.span() >= size_t(std::numeric_limits::max()))) { + if (DstExecCanAccessSrc) { + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, dst_execution_space, DstType::Rank, int64_t>( + dst, src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, dst_execution_space, - DstType::Rank, int64_t >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, dst_execution_space, DstType::Rank, int64_t>( + dst, src); } else { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, src_execution_space, - DstType::Rank, int64_t >( dst , src ); + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, src_execution_space, DstType::Rank, int64_t>( + dst, src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, src_execution_space, - DstType::Rank, int64_t >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, src_execution_space, DstType::Rank, int64_t>( + dst, src); } } else { - if(DstExecCanAccessSrc) { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, dst_execution_space, - DstType::Rank, int >( dst , src ); + if (DstExecCanAccessSrc) { + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, dst_execution_space, DstType::Rank, int>(dst, + src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, dst_execution_space, - DstType::Rank, int >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, dst_execution_space, DstType::Rank, int>(dst, + src); } else { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutRight, src_execution_space, - DstType::Rank, int >( dst , src ); + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutRight, src_execution_space, DstType::Rank, int>(dst, + src); else - Kokkos::Impl::ViewCopy< typename DstType::uniform_runtime_nomemspace_type, typename SrcType::uniform_runtime_const_nomemspace_type, Kokkos::LayoutLeft, src_execution_space, - DstType::Rank, int >( dst , src ); + Kokkos::Impl::ViewCopy< + typename DstType::uniform_runtime_nomemspace_type, + typename SrcType::uniform_runtime_const_nomemspace_type, + Kokkos::LayoutLeft, src_execution_space, DstType::Rank, int>(dst, + src); } - } } -template +template struct CommonSubview; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview dst_subview_type; + typedef typename Kokkos::Subview src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, Args... ): - dst_sub(dst,arg0),src_sub(src,arg0) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + Args...) + : dst_sub(dst, arg0), src_sub(src, arg0) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview dst_subview_type; + typedef typename Kokkos::Subview src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, Args... ): - dst_sub(dst,arg0,arg1),src_sub(src,arg0,arg1) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, Args...) + : dst_sub(dst, arg0, arg1), src_sub(src, arg0, arg1) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview dst_subview_type; + typedef typename Kokkos::Subview src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, Args... ): - dst_sub(dst,arg0,arg1,arg2),src_sub(src,arg0,arg1,arg2) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, Args...) + : dst_sub(dst, arg0, arg1, arg2), src_sub(src, arg0, arg1, arg2) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, - const Args ...): - dst_sub(dst,arg0,arg1,arg2,arg3),src_sub(src,arg0,arg1,arg2,arg3) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3), + src_sub(src, arg0, arg1, arg2, arg3) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, - const Args ...): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4),src_sub(src,arg0,arg1,arg2,arg3,arg4) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4), + src_sub(src, arg0, arg1, arg2, arg3, arg4) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, - const Args ...): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4,arg5),src_sub(src,arg0,arg1,arg2,arg3,arg4,arg5) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5, const Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4, arg5), + src_sub(src, arg0, arg1, arg2, arg3, arg4, arg5) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, - const Arg6& arg6, Args...): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4,arg5,arg6),src_sub(src,arg0,arg1,arg2,arg3,arg4,arg5,arg6) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5, const Arg6& arg6, Args...) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4, arg5, arg6), + src_sub(src, arg0, arg1, arg2, arg3, arg4, arg5, arg6) {} }; -template -struct CommonSubview { - typedef typename Kokkos::Subview dst_subview_type; - typedef typename Kokkos::Subview src_subview_type; +template +struct CommonSubview { + typedef typename Kokkos::Subview + dst_subview_type; + typedef typename Kokkos::Subview + src_subview_type; dst_subview_type dst_sub; src_subview_type src_sub; - CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, const Arg1& arg1, - const Arg2& arg2, const Arg3& arg3, const Arg4& arg4, const Arg5& arg5, - const Arg6& arg6, const Arg7& arg7): - dst_sub(dst,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7),src_sub(src,arg0,arg1,arg2,arg3,arg4,arg5,arg6,arg7) {} + CommonSubview(const DstType& dst, const SrcType& src, const Arg0& arg0, + const Arg1& arg1, const Arg2& arg2, const Arg3& arg3, + const Arg4& arg4, const Arg5& arg5, const Arg6& arg6, + const Arg7& arg7) + : dst_sub(dst, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7), + src_sub(src, arg0, arg1, arg2, arg3, arg4, arg5, arg6, arg7) {} }; - -template +template struct ViewRemap; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - view_copy(dst,src); + if (dst.extent(0) == src.extent(0)) { + view_copy(dst, src); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + typedef CommonSubview sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(1) == src.extent(1)) { - view_copy(dst,src); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(1) == src.extent(1)) { + view_copy(dst, src); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL,ext1); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(1) == src.extent(1)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(1) == src.extent(1)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,ext1); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(2) == src.extent(2)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL,ext1,Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(2) == src.extent(2)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, + Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL,ext1,ext2); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(2) == src.extent(2)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,ext1,Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(2) == src.extent(2)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0,ext1,ext2); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(3) == src.extent(3)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2, + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(3) == src.extent(3)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2, - ext3); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(7) == src.extent(7)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(7) == src.extent(7)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2, - ext3); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(4) == src.extent(4)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3, + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(4) == src.extent(4)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3, + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, ext4); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(4) == src.extent(4)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3, + if (dst.extent(4) == src.extent(4)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3, - ext4); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(5) == src.extent(5)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(5) == src.extent(5)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4, - ext5); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(5) == src.extent(5)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4, + if (dst.extent(5) == src.extent(5)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4, + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, ext5); - view_copy(common_subview.dst_sub,common_subview.src_sub); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(6) == src.extent(6)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(6) == src.extent(6)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5, - ext6); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, ext6); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(6) == src.extent(6)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(6) == src.extent(6)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5, - ext6); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, ext6); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -template -struct ViewRemap { - typedef Kokkos::pair p_type; +template +struct ViewRemap { + typedef Kokkos::pair p_type; ViewRemap(const DstType& dst, const SrcType& src) { - if(dst.extent(0) == src.extent(0)) { - if(dst.extent(7) == src.extent(7)) { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5,ext6, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(0) == src.extent(0)) { + if (dst.extent(7) == src.extent(7)) { + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, ext6, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - p_type ext7(0,std::min(dst.extent(7),src.extent(7))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,Kokkos::ALL, - ext1,ext2,ext3,ext4,ext5,ext6, - ext7); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + p_type ext7(0, std::min(dst.extent(7), src.extent(7))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, Kokkos::ALL, ext1, ext2, ext3, + ext4, ext5, ext6, ext7); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } else { - if(dst.extent(7) == src.extent(7)) { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5,ext6, - Kokkos::ALL); - view_copy(common_subview.dst_sub,common_subview.src_sub); + if (dst.extent(7) == src.extent(7)) { + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, ext6, Kokkos::ALL); + view_copy(common_subview.dst_sub, common_subview.src_sub); } else { - p_type ext0(0,std::min(dst.extent(0),src.extent(0))); - p_type ext1(0,std::min(dst.extent(1),src.extent(1))); - p_type ext2(0,std::min(dst.extent(2),src.extent(2))); - p_type ext3(0,std::min(dst.extent(3),src.extent(3))); - p_type ext4(0,std::min(dst.extent(4),src.extent(4))); - p_type ext5(0,std::min(dst.extent(5),src.extent(5))); - p_type ext6(0,std::min(dst.extent(6),src.extent(6))); - p_type ext7(0,std::min(dst.extent(7),src.extent(7))); - typedef CommonSubview sv_adapter_type; - sv_adapter_type common_subview(dst,src,ext0, - ext1,ext2,ext3,ext4,ext5,ext6, - ext7); - view_copy(common_subview.dst_sub,common_subview.src_sub); + p_type ext0(0, std::min(dst.extent(0), src.extent(0))); + p_type ext1(0, std::min(dst.extent(1), src.extent(1))); + p_type ext2(0, std::min(dst.extent(2), src.extent(2))); + p_type ext3(0, std::min(dst.extent(3), src.extent(3))); + p_type ext4(0, std::min(dst.extent(4), src.extent(4))); + p_type ext5(0, std::min(dst.extent(5), src.extent(5))); + p_type ext6(0, std::min(dst.extent(6), src.extent(6))); + p_type ext7(0, std::min(dst.extent(7), src.extent(7))); + typedef CommonSubview + sv_adapter_type; + sv_adapter_type common_subview(dst, src, ext0, ext1, ext2, ext3, ext4, + ext5, ext6, ext7); + view_copy(common_subview.dst_sub, common_subview.src_sub); } } } }; -} +} // namespace Impl /** \brief Deep copy a value from Host memory into a view. */ -template< class DT , class ... DP > -inline -void deep_copy - ( const View & dst - , typename ViewTraits::const_value_type & value - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - typedef View ViewType; - if(dst.data() == NULL ) { +template +inline void deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if::specialize, void>::value>::type* = 0) { + typedef View ViewType; + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle( + typename ViewType::memory_space().name()), + dst.label(), dst.data(), + Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), "Scalar", + &value, dst.span() * sizeof(typename ViewType::value_type)); + } +#endif + + if (dst.data() == NULL) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } Kokkos::fence(); - static_assert( - std::is_same< typename ViewType::non_const_value_type , - typename ViewType::value_type >::value - , "deep_copy requires non-const type" ); - - // If contiguous we can simply do a 1D flat loop - if(dst.span_is_contiguous()) { - typedef Kokkos::View::value, + "deep_copy requires non-const type"); + + // If contigous we can simply do a 1D flat loop + if (dst.span_is_contiguous()) { + typedef Kokkos::View< + typename ViewType::value_type*, Kokkos::LayoutRight, Kokkos::Device::type>, - Kokkos::MemoryTraits<0> > - ViewTypeFlat; - - ViewTypeFlat dst_flat(dst.data(),dst.size()); - if(dst.span() < std::numeric_limits::max()) { - Kokkos::Impl::ViewFill< ViewTypeFlat , Kokkos::LayoutRight, typename ViewType::execution_space, ViewTypeFlat::Rank, int >( dst_flat , value ); + typename std::conditional< + ViewType::Rank == 0, typename ViewType::memory_space, + Kokkos::AnonymousSpace>::type>, + Kokkos::MemoryTraits<0>> + ViewTypeFlat; + + ViewTypeFlat dst_flat(dst.data(), dst.size()); + if (dst.span() < static_cast(std::numeric_limits::max())) { + Kokkos::Impl::ViewFill(dst_flat, value); } else - Kokkos::Impl::ViewFill< ViewTypeFlat , Kokkos::LayoutRight, typename ViewType::execution_space, ViewTypeFlat::Rank, int64_t >( dst_flat , value ); + Kokkos::Impl::ViewFill(dst_flat, value); Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } // Figure out iteration order to do the ViewFill - int64_t strides[ViewType::Rank+1]; + int64_t strides[ViewType::Rank + 1]; dst.stride(strides); Kokkos::Iterate iterate; - if ( std::is_same::value ) { + if (std::is_same::value) { iterate = Kokkos::Iterate::Right; - } else if ( std::is_same::value ) { + } else if (std::is_same::value) { iterate = Kokkos::Iterate::Left; - } else if ( std::is_same::value ) { - if( strides[0] > strides[ViewType::Rank>0?ViewType::Rank-1:0] ) + } else if (std::is_same::value) { + if (strides[0] > strides[ViewType::Rank > 0 ? ViewType::Rank - 1 : 0]) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } else { - if( std::is_same::value ) + if (std::is_same::value) iterate = Kokkos::Iterate::Right; else iterate = Kokkos::Iterate::Left; } - // Lets call the right ViewFill functor based on integer space needed and iteration type - typedef typename std::conditional::type ViewTypeUniform; - if(dst.span() > std::numeric_limits::max()) { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutRight, typename ViewType::execution_space, ViewType::Rank, int64_t >( dst , value ); + // Lets call the right ViewFill functor based on integer space needed and + // iteration type + typedef typename std::conditional< + ViewType::Rank == 0, typename ViewType::uniform_runtime_type, + typename ViewType::uniform_runtime_nomemspace_type>::type ViewTypeUniform; + if (dst.span() > static_cast(std::numeric_limits::max())) { + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewFill(dst, value); else - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutLeft, typename ViewType::execution_space, ViewType::Rank, int64_t >( dst , value ); + Kokkos::Impl::ViewFill(dst, value); } else { - if(iterate == Kokkos::Iterate::Right) - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutRight, typename ViewType::execution_space, ViewType::Rank, int >( dst , value ); + if (iterate == Kokkos::Iterate::Right) + Kokkos::Impl::ViewFill(dst, value); else - Kokkos::Impl::ViewFill< ViewTypeUniform, Kokkos::LayoutLeft, typename ViewType::execution_space, ViewType::Rank, int >( dst , value ); + Kokkos::Impl::ViewFill(dst, value); } Kokkos::fence(); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } /** \brief Deep copy into a value in Host memory from a view. */ -template< class ST , class ... SP > -inline -void deep_copy - ( typename ViewTraits::non_const_value_type & dst - , const View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - static_assert( ViewTraits::rank == 0 - , "ERROR: Non-rank-zero view in deep_copy( value , View )" ); - - if(src.data() == NULL) { +template +inline void deep_copy( + typename ViewTraits::non_const_value_type& dst, + const View& src, + typename std::enable_if::specialize, void>::value>::type* = 0) { + typedef ViewTraits src_traits; + typedef typename src_traits::memory_space src_memory_space; + + static_assert(src_traits::rank == 0, + "ERROR: Non-rank-zero view in deep_copy( value , View )"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), "Scalar", + &dst, Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), + src.span() * sizeof(typename src_traits::value_type)); + } +#endif + + if (src.data() == NULL) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - typedef ViewTraits src_traits ; - typedef typename src_traits::memory_space src_memory_space ; - Kokkos::Impl::DeepCopy< HostSpace , src_memory_space >( & dst , src.data() , sizeof(ST) ); + Kokkos::Impl::DeepCopy(&dst, src.data(), + sizeof(ST)); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- /** \brief A deep copy between views of compatible type, and rank zero. */ -template< class DT , class ... DP , class ST , class ... SP > -inline -void deep_copy - ( const View & dst - , const View & src - , typename std::enable_if<( - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) == unsigned(0) && - unsigned(ViewTraits::rank) == unsigned(0) ) - )>::type * = 0 ) -{ - static_assert( - std::is_same< typename ViewTraits::value_type , - typename ViewTraits::non_const_value_type >::value - , "deep_copy requires matching non-const destination type" ); - - if(dst.data() == NULL && src.data() == NULL) { +template +inline void deep_copy( + const View& dst, const View& src, + typename std::enable_if<( + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) == unsigned(0) && + unsigned(ViewTraits::rank) == unsigned(0)))>::type* = 0) { + typedef View dst_type; + typedef View src_type; + + typedef typename dst_type::value_type value_type; + typedef typename dst_type::memory_space dst_memory_space; + typedef typename src_type::memory_space src_memory_space; + + static_assert(std::is_same::value, + "deep_copy requires matching non-const destination type"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), + src.span() * sizeof(typename dst_type::value_type)); + } +#endif + + if (dst.data() == NULL && src.data() == NULL) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - typedef View dst_type ; - typedef View src_type ; - - typedef typename dst_type::value_type value_type ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - Kokkos::fence(); - if ( dst.data() != src.data() ) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space >( dst.data() , src.data() , sizeof(value_type) ); + if (dst.data() != src.data()) { + Kokkos::Impl::DeepCopy( + dst.data(), src.data(), sizeof(value_type)); Kokkos::fence(); } +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- -/** \brief A deep copy between views of the default specialization, compatible type, - * same non-zero rank, same contiguous layout. +/** \brief A deep copy between views of the default specialization, compatible + * type, same non-zero rank, same contiguous layout. */ -template< class DT , class ... DP , class ST , class ... SP > -inline -void deep_copy - ( const View & dst - , const View & src - , typename std::enable_if<( - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) != 0 || - unsigned(ViewTraits::rank) != 0 ) - )>::type * = 0 ) -{ - typedef View dst_type ; - typedef View src_type ; - - static_assert( - std::is_same< typename dst_type::value_type , - typename dst_type::non_const_value_type >::value - , "deep_copy requires non-const destination type" ); - - static_assert( - ( unsigned(dst_type::rank) == - unsigned(src_type::rank) ) - , "deep_copy requires Views of equal rank" ); - - - typedef typename dst_type::execution_space dst_execution_space ; - typedef typename src_type::execution_space src_execution_space ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - typedef typename dst_type::value_type dst_value_type ; - typedef typename src_type::value_type src_value_type ; - if(dst.data() == NULL || src.data() == NULL) { +template +inline void deep_copy( + const View& dst, const View& src, + typename std::enable_if<( + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) != 0 || + unsigned(ViewTraits::rank) != 0))>::type* = 0) { + typedef View dst_type; + typedef View src_type; + typedef typename dst_type::execution_space dst_execution_space; + typedef typename src_type::execution_space src_execution_space; + typedef typename dst_type::memory_space dst_memory_space; + typedef typename src_type::memory_space src_memory_space; + typedef typename dst_type::value_type dst_value_type; + typedef typename src_type::value_type src_value_type; + + static_assert(std::is_same::value, + "deep_copy requires non-const destination type"); + + static_assert((unsigned(dst_type::rank) == unsigned(src_type::rank)), + "deep_copy requires Views of equal rank"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), + src.span() * sizeof(typename dst_type::value_type)); + } +#endif + + if (dst.data() == NULL || src.data() == NULL) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // do nothing #else // throw if dimension mismatch - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::accessible }; + enum { + DstExecCanAccessSrc = + Kokkos::Impl::SpaceAccessibility::accessible + }; - enum { SrcExecCanAccessDst = - Kokkos::Impl::SpaceAccessibility< src_execution_space , dst_memory_space >::accessible }; + enum { + SrcExecCanAccessDst = + Kokkos::Impl::SpaceAccessibility::accessible + }; // Checking for Overlapping Views. dst_value_type* dst_start = dst.data(); dst_value_type* dst_end = dst.data() + dst.span(); src_value_type* src_start = src.data(); src_value_type* src_end = src.data() + src.span(); - if( ((std::ptrdiff_t)dst_start == (std::ptrdiff_t)src_start) && - ((std::ptrdiff_t)dst_end == (std::ptrdiff_t)src_end) && - (dst.span_is_contiguous() && src.span_is_contiguous()) ) { + if (((std::ptrdiff_t)dst_start == (std::ptrdiff_t)src_start) && + ((std::ptrdiff_t)dst_end == (std::ptrdiff_t)src_end) && + (dst.span_is_contiguous() && src.span_is_contiguous())) { Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - if( ( ( (std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end ) && ( (std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start ) ) && - ( ( dst.span_is_contiguous() && src.span_is_contiguous() ))) { + if ((((std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end) && + ((std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start)) && + ((dst.span_is_contiguous() && src.span_is_contiguous()))) { std::string message("Error: Kokkos::deep_copy of overlapping views: "); - message += dst.label(); message += "("; - message += std::to_string((std::ptrdiff_t)dst_start); message += ","; - message += std::to_string((std::ptrdiff_t)dst_end); message += ") "; - message += src.label(); message += "("; - message += std::to_string((std::ptrdiff_t)src_start); message += ","; - message += std::to_string((std::ptrdiff_t)src_end); message += ") "; + message += dst.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)dst_start); + message += ","; + message += std::to_string((std::ptrdiff_t)dst_end); + message += ") "; + message += src.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)src_start); + message += ","; + message += std::to_string((std::ptrdiff_t)src_end); + message += ") "; Kokkos::Impl::throw_runtime_exception(message); } // Check for same extents - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { + if ((src.extent(0) != dst.extent(0)) || (src.extent(1) != dst.extent(1)) || + (src.extent(2) != dst.extent(2)) || (src.extent(3) != dst.extent(3)) || + (src.extent(4) != dst.extent(4)) || (src.extent(5) != dst.extent(5)) || + (src.extent(6) != dst.extent(6)) || (src.extent(7) != dst.extent(7))) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE Kokkos::fence(); - if ( DstExecCanAccessSrc ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type >( dst , src ); - } - else if ( SrcExecCanAccessDst ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type , src_execution_space >( dst , src ); - } - else { - Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation"); + if (DstExecCanAccessSrc) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, src); + } else if (SrcExecCanAccessDst) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, + src); + } else { + Kokkos::Impl::throw_runtime_exception( + "deep_copy given views that would require a temporary allocation"); } Kokkos::fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; #else - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::value && - ( - std::is_same< typename dst_type::array_layout , - typename src_type::array_layout >::value - || - ( dst_type::rank == 1 && - src_type::rank == 1 ) - ) && - dst.span_is_contiguous() && - src.span_is_contiguous() && - ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && - ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && - ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && - ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && - ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && - ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && - ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && - ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7())) - ) { + // If same type, equal layout, equal dimensions, equal span, and contiguous + // memory then can byte-wise copy + + if (std::is_same::value && + (std::is_same::value || + (dst_type::rank == 1 && src_type::rank == 1)) && + dst.span_is_contiguous() && src.span_is_contiguous() && + ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && + ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && + ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && + ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && + ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && + ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && + ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && + ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7()))) { const size_t nbytes = sizeof(typename dst_type::value_type) * dst.span(); Kokkos::fence(); - if((void*)dst.data()!=(void*)src.data()) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space > - ( dst.data() , src.data() , nbytes ); + if ((void*)dst.data() != (void*)src.data()) { + Kokkos::Impl::DeepCopy( + dst.data(), src.data(), nbytes); } Kokkos::fence(); } else { @@ -1536,779 +1839,779 @@ void deep_copy Impl::view_copy(dst, src); Kokkos::fence(); } +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- namespace Experimental { -/** \brief A local deep copy between views of the default specialization, compatible type, - * same non-zero rank. +/** \brief A local deep copy between views of the default specialization, + * compatible type, same non-zero rank. */ -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const TeamType& team, const View & dst, const View & src) { - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, src.span()), [&] (const int& i) { - dst.data()[i] = src.data()[i]; - }); +template +void KOKKOS_INLINE_FUNCTION +local_deep_copy_contiguous(const TeamType& team, const View& dst, + const View& src) { + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, src.span()), + [&](const int& i) { dst.data()[i] = src.data()[i]; }); } //---------------------------------------------------------------------------- -template< class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const View & dst, const View & src) { - - for(size_t i=0;i +void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous( + const View& dst, const View& src) { + for (size_t i = 0; i < src.span(); ++i) { + dst.data()[i] = src.data()[i]; + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 && - unsigned(ViewTraits::rank) == 1 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 1 && + unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - dst(i) = src(i); - }); - team.team_barrier(); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), + [&](const int& i) { dst(i) = src(i); }); + team.team_barrier(); } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 && - unsigned(ViewTraits::rank) == 2 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 2 && + unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1); + const size_t N = dst.extent(0) * dst.extent(1); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int i1 = i/dst.extent(0); - dst(i0,i1) = src(i0,i1); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int i1 = i / dst.extent(0); + dst(i0, i1) = src(i0, i1); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 && - unsigned(ViewTraits::rank) == 3 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 3 && + unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - int i2 = itmp/dst.extent(1); - dst(i0,i1,i2) = src(i0,i1,i2); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + int i2 = itmp / dst.extent(1); + dst(i0, i1, i2) = src(i0, i1, i2); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 && - unsigned(ViewTraits::rank) == 4 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 4 && + unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3); + const size_t N = + dst.extent(0) * dst.extent(1) * dst.extent(2) * dst.extent(3); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - int i3 = itmp/dst.extent(2); - dst(i0,i1,i2,i3) = src(i0,i1,i2,i3); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + int i3 = itmp / dst.extent(2); + dst(i0, i1, i2, i3) = src(i0, i1, i2, i3); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 && - unsigned(ViewTraits::rank) == 5 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 5 && + unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - int i4 = itmp/dst.extent(3); - dst(i0,i1,i2,i3,i4) = src(i0,i1,i2,i3,i4); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + int i4 = itmp / dst.extent(3); + dst(i0, i1, i2, i3, i4) = src(i0, i1, i2, i3, i4); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 && - unsigned(ViewTraits::rank) == 6 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 6 && + unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - int i5 = itmp/dst.extent(4); - dst(i0,i1,i2,i3,i4,i5) = src(i0,i1,i2,i3,i4,i5); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + int i5 = itmp / dst.extent(4); + dst(i0, i1, i2, i3, i4, i5) = src(i0, i1, i2, i3, i4, i5); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 && - unsigned(ViewTraits::rank) == 7 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 7 && + unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5)*dst.extent(6); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5) * + dst.extent(6); - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,src); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - itmp = itmp/dst.extent(4); - int i5 = itmp%dst.extent(5); - int i6 = itmp/dst.extent(5); - dst(i0,i1,i2,i3,i4,i5,i6) = src(i0,i1,i2,i3,i4,i5,i6); - }); - team.team_barrier(); - } + if (dst.span_is_contiguous() && src.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, src); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + itmp = itmp / dst.extent(4); + int i5 = itmp % dst.extent(5); + int i6 = itmp / dst.extent(5); + dst(i0, i1, i2, i3, i4, i5, i6) = src(i0, i1, i2, i3, i4, i5, i6); + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class DT , class ... DP , class ST , class ... SP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 && - unsigned(ViewTraits::rank) == 1 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 1 && + unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - - for(size_t i=0;i -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 && - unsigned(ViewTraits::rank) == 2 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 2 && + unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 && - unsigned(ViewTraits::rank) == 3 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 3 && + unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 && - unsigned(ViewTraits::rank) == 4 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 4 && + unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 && - unsigned(ViewTraits::rank) == 5 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 5 && + unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 && - unsigned(ViewTraits::rank) == 6 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 6 && + unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - const View & src, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 && - unsigned(ViewTraits::rank) == 7 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, const View& src, + typename std::enable_if<(unsigned(ViewTraits::rank) == 7 && + unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() && src.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,src); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const TeamType& team, const View & dst, typename ViewTraits::const_value_type & value) { - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, dst.span()), [&] (const int& i) { - dst.data()[i] = value; - }); +template +void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value) { + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, dst.span()), + [&](const int& i) { dst.data()[i] = value; }); } //---------------------------------------------------------------------------- -template< class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous(const View & dst, typename ViewTraits::const_value_type & value) { - - for(size_t i=0;i +void KOKKOS_INLINE_FUNCTION local_deep_copy_contiguous( + const View& dst, + typename ViewTraits::const_value_type& value) { + for (size_t i = 0; i < dst.span(); ++i) { + dst.data()[i] = value; + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - dst(i) = value; - }); - team.team_barrier(); + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), + [&](const int& i) { dst(i) = value; }); + team.team_barrier(); } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1); + const size_t N = dst.extent(0) * dst.extent(1); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int i1 = i/dst.extent(0); - dst(i0,i1) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int i1 = i / dst.extent(0); + dst(i0, i1) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - int i2 = itmp/dst.extent(1); - dst(i0,i1,i2) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + int i2 = itmp / dst.extent(1); + dst(i0, i1, i2) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3); + const size_t N = + dst.extent(0) * dst.extent(1) * dst.extent(2) * dst.extent(3); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - int i3 = itmp/dst.extent(2); - dst(i0,i1,i2,i3) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + int i3 = itmp / dst.extent(2); + dst(i0, i1, i2, i3) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - int i4 = itmp/dst.extent(3); - dst(i0,i1,i2,i3,i4) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + int i4 = itmp / dst.extent(3); + dst(i0, i1, i2, i3, i4) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - int i5 = itmp/dst.extent(4); - dst(i0,i1,i2,i3,i4,i5) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + int i5 = itmp / dst.extent(4); + dst(i0, i1, i2, i3, i4, i5) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class TeamType, class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const TeamType& team, const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const TeamType& team, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0)*dst.extent(1)*dst.extent(2)*dst.extent(3)*dst.extent(4)*dst.extent(5)*dst.extent(6); + const size_t N = dst.extent(0) * dst.extent(1) * dst.extent(2) * + dst.extent(3) * dst.extent(4) * dst.extent(5) * + dst.extent(6); - if ( dst.span_is_contiguous() ) { - team.team_barrier(); - local_deep_copy_contiguous(team,dst,value); - team.team_barrier(); - } else { - team.team_barrier(); - Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&] (const int& i) { - int i0 = i%dst.extent(0); - int itmp = i/dst.extent(0); - int i1 = itmp%dst.extent(1); - itmp = itmp/dst.extent(1); - int i2 = itmp%dst.extent(2); - itmp = itmp/dst.extent(2); - int i3 = itmp%dst.extent(3); - itmp = itmp/dst.extent(3); - int i4 = itmp%dst.extent(4); - itmp = itmp/dst.extent(4); - int i5 = itmp%dst.extent(5); - int i6 = itmp/dst.extent(5); - dst(i0,i1,i2,i3,i4,i5,i6) = value; - }); - team.team_barrier(); - } + if (dst.span_is_contiguous()) { + team.team_barrier(); + local_deep_copy_contiguous(team, dst, value); + team.team_barrier(); + } else { + team.team_barrier(); + Kokkos::parallel_for(Kokkos::TeamThreadRange(team, N), [&](const int& i) { + int i0 = i % dst.extent(0); + int itmp = i / dst.extent(0); + int i1 = itmp % dst.extent(1); + itmp = itmp / dst.extent(1); + int i2 = itmp % dst.extent(2); + itmp = itmp / dst.extent(2); + int i3 = itmp % dst.extent(3); + itmp = itmp / dst.extent(3); + int i4 = itmp % dst.extent(4); + itmp = itmp / dst.extent(4); + int i5 = itmp % dst.extent(5); + int i6 = itmp / dst.extent(5); + dst(i0, i1, i2, i3, i4, i5, i6) = value; + }); + team.team_barrier(); + } } //---------------------------------------------------------------------------- -template< class DT , class ... DP > -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 1 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 1)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - const size_t N = dst.extent(0); + const size_t N = dst.extent(0); - - for(size_t i=0;i -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 2 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 2)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 3 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 3)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 4 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 4)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 5 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 5)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 6 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 6)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 -void KOKKOS_INLINE_FUNCTION local_deep_copy (const View & dst, - typename ViewTraits::const_value_type & value, - typename std::enable_if<( unsigned(ViewTraits::rank) == 7 - )>::type * = 0 ) -{ - if( dst.data() == nullptr ) { - return; - } +template +void KOKKOS_INLINE_FUNCTION local_deep_copy( + const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if<(unsigned(ViewTraits::rank) == + 7)>::type* = 0) { + if (dst.data() == nullptr) { + return; + } - if ( dst.span_is_contiguous() ) { - local_deep_copy_contiguous(dst,value); - } else { - - for(size_t i0=0;i0 & dst, namespace Kokkos { /** \brief Deep copy a value from Host memory into a view. */ -template< class ExecSpace ,class DT , class ... DP > -inline -void deep_copy - ( const ExecSpace & - , const View & dst - , typename ViewTraits::const_value_type & value - , typename std::enable_if< - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - static_assert( - std::is_same< typename ViewTraits::non_const_value_type , - typename ViewTraits::value_type >::value - , "deep_copy requires non-const type" ); - +template +inline void deep_copy( + const ExecSpace&, const View& dst, + typename ViewTraits::const_value_type& value, + typename std::enable_if< + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, + void>::value>::type* = 0) { + typedef ViewTraits dst_traits; + typedef typename dst_traits::memory_space dst_memory_space; + static_assert(std::is_same::value, + "deep_copy requires non-const type"); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), + "(none)", &value, dst.span() * sizeof(typename dst_traits::value_type)); + } +#endif ExecSpace().fence(); - typedef typename View::uniform_runtime_nomemspace_type ViewTypeUniform; - Kokkos::Impl::ViewFill< ViewTypeUniform >( dst , value ); + typedef + typename View::uniform_runtime_nomemspace_type ViewTypeUniform; + Kokkos::Impl::ViewFill(dst, value); ExecSpace().fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } /** \brief Deep copy into a value in Host memory from a view. */ -template< class ExecSpace , class ST , class ... SP > -inline -void deep_copy - ( const ExecSpace & exec_space - , typename ViewTraits::non_const_value_type & dst - , const View & src - , typename std::enable_if< - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0 ) -{ - static_assert( ViewTraits::rank == 0 - , "ERROR: Non-rank-zero view in deep_copy( value , View )" ); - - if(src.data() == NULL) { +template +inline void deep_copy( + const ExecSpace& exec_space, + typename ViewTraits::non_const_value_type& dst, + const View& src, + typename std::enable_if< + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, + void>::value>::type* = 0) { + typedef ViewTraits src_traits; + typedef typename src_traits::memory_space src_memory_space; + static_assert(src_traits::rank == 0, + "ERROR: Non-rank-zero view in deep_copy( value , View )"); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(Kokkos::HostSpace().name()), "(none)", + &dst, Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), sizeof(ST)); + } +#endif + + if (src.data() == NULL) { exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } - typedef ViewTraits src_traits ; - typedef typename src_traits::memory_space src_memory_space ; - Kokkos::Impl::DeepCopy< HostSpace , src_memory_space , ExecSpace > - ( exec_space , & dst , src.data() , sizeof(ST) ); + Kokkos::Impl::DeepCopy( + exec_space, &dst, src.data(), sizeof(ST)); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- /** \brief A deep copy between views of compatible type, and rank zero. */ -template< class ExecSpace , class DT , class ... DP , class ST , class ... SP > -inline -void deep_copy - ( const ExecSpace & exec_space - , const View & dst - , const View & src - , typename std::enable_if<( - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) == unsigned(0) && - unsigned(ViewTraits::rank) == unsigned(0) ) - )>::type * = 0 ) -{ - static_assert( - std::is_same< typename ViewTraits::value_type , - typename ViewTraits::non_const_value_type >::value - , "deep_copy requires matching non-const destination type" ); - - typedef View dst_type ; - typedef View src_type ; - - typedef typename dst_type::value_type value_type ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - if(dst.data() == NULL && src.data() == NULL) { +template +inline void deep_copy( + const ExecSpace& exec_space, const View& dst, + const View& src, + typename std::enable_if<( + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) == unsigned(0) && + unsigned(ViewTraits::rank) == unsigned(0)))>::type* = 0) { + typedef ViewTraits src_traits; + typedef ViewTraits dst_traits; + + typedef typename src_traits::memory_space src_memory_space; + typedef typename dst_traits::memory_space dst_memory_space; + static_assert(std::is_same::value, + "deep_copy requires matching non-const destination type"); + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), sizeof(DT)); + } +#endif + + if (dst.data() == NULL && src.data() == NULL) { exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; } exec_space.fence(); - if ( dst.data() != src.data() ) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space , ExecSpace > - ( exec_space , dst.data() , src.data() , sizeof(value_type) ); + if (dst.data() != src.data()) { + Kokkos::Impl::DeepCopy( + exec_space, dst.data(), src.data(), + sizeof(typename dst_traits::value_type)); } exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } //---------------------------------------------------------------------------- -/** \brief A deep copy between views of the default specialization, compatible type, - * same non-zero rank +/** \brief A deep copy between views of the default specialization, compatible + * type, same non-zero rank */ -template< class ExecSpace , class DT, class ... DP, class ST, class ... SP > -inline -void deep_copy - ( const ExecSpace & exec_space - , const View & dst - , const View & src - , typename std::enable_if<( - Kokkos::Impl::is_execution_space< ExecSpace >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename ViewTraits::specialize , void >::value && - ( unsigned(ViewTraits::rank) != 0 || - unsigned(ViewTraits::rank) != 0 ) - )>::type * = 0 ) -{ - typedef View dst_type ; - typedef View src_type ; - - static_assert( - std::is_same< typename dst_type::value_type , - typename dst_type::non_const_value_type >::value - , "deep_copy requires non-const destination type" ); - - static_assert( - ( unsigned(dst_type::rank) == - unsigned(src_type::rank) ) - , "deep_copy requires Views of equal rank" ); - - typedef typename dst_type::execution_space dst_execution_space ; - typedef typename src_type::execution_space src_execution_space ; - typedef typename dst_type::memory_space dst_memory_space ; - typedef typename src_type::memory_space src_memory_space ; - typedef typename dst_type::value_type dst_value_type ; - typedef typename src_type::value_type src_value_type ; - - if(dst.data() == NULL || src.data() == NULL) { +template +inline void deep_copy( + const ExecSpace& exec_space, const View& dst, + const View& src, + typename std::enable_if<( + Kokkos::Impl::is_execution_space::value && + std::is_same::specialize, void>::value && + std::is_same::specialize, void>::value && + (unsigned(ViewTraits::rank) != 0 || + unsigned(ViewTraits::rank) != 0))>::type* = 0) { + typedef View dst_type; + typedef View src_type; + + static_assert(std::is_same::value, + "deep_copy requires non-const destination type"); + + static_assert((unsigned(dst_type::rank) == unsigned(src_type::rank)), + "deep_copy requires Views of equal rank"); + + typedef typename dst_type::execution_space dst_execution_space; + typedef typename src_type::execution_space src_execution_space; + typedef typename dst_type::memory_space dst_memory_space; + typedef typename src_type::memory_space src_memory_space; + typedef typename dst_type::value_type dst_value_type; + typedef typename src_type::value_type src_value_type; + +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::beginDeepCopy( + Kokkos::Profiling::SpaceHandle(dst_memory_space().name()), dst.label(), + dst.data(), Kokkos::Profiling::SpaceHandle(src_memory_space().name()), + src.label(), src.data(), dst.span() * sizeof(dst_value_type)); + } +#endif + + if (dst.data() == NULL || src.data() == NULL) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // do nothing #else // throw if dimension mismatch - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::accessible && - Kokkos::Impl::SpaceAccessibility< ExecSpace , src_memory_space >::accessible + enum { + ExecCanAccessSrcDst = + Kokkos::Impl::SpaceAccessibility::accessible && + Kokkos::Impl::SpaceAccessibility::accessible + }; + enum { + DstExecCanAccessSrc = + Kokkos::Impl::SpaceAccessibility::accessible }; - enum { DstExecCanAccessSrc = - Kokkos::Impl::SpaceAccessibility< dst_execution_space , src_memory_space >::accessible }; - enum { SrcExecCanAccessDst = - Kokkos::Impl::SpaceAccessibility< src_execution_space , dst_memory_space >::accessible }; + enum { + SrcExecCanAccessDst = + Kokkos::Impl::SpaceAccessibility::accessible + }; // Checking for Overlapping Views. dst_value_type* dst_start = dst.data(); dst_value_type* dst_end = dst.data() + dst.span(); src_value_type* src_start = src.data(); src_value_type* src_end = src.data() + src.span(); - if( ( ( (std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end ) && ( (std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start ) ) && - ( ( dst.span_is_contiguous() && src.span_is_contiguous() ))) { + if ((((std::ptrdiff_t)dst_start < (std::ptrdiff_t)src_end) && + ((std::ptrdiff_t)dst_end > (std::ptrdiff_t)src_start)) && + ((dst.span_is_contiguous() && src.span_is_contiguous()))) { std::string message("Error: Kokkos::deep_copy of overlapping views: "); - message += dst.label(); message += "("; - message += std::to_string((std::ptrdiff_t)dst_start); message += ","; - message += std::to_string((std::ptrdiff_t)dst_end); message += ") "; - message += src.label(); message += "("; - message += std::to_string((std::ptrdiff_t)src_start); message += ","; - message += std::to_string((std::ptrdiff_t)src_end); message += ") "; + message += dst.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)dst_start); + message += ","; + message += std::to_string((std::ptrdiff_t)dst_end); + message += ") "; + message += src.label(); + message += "("; + message += std::to_string((std::ptrdiff_t)src_start); + message += ","; + message += std::to_string((std::ptrdiff_t)src_end); + message += ") "; Kokkos::Impl::throw_runtime_exception(message); } // Check for same extents - if ( (src.extent(0) != dst.extent(0)) || - (src.extent(1) != dst.extent(1)) || - (src.extent(2) != dst.extent(2)) || - (src.extent(3) != dst.extent(3)) || - (src.extent(4) != dst.extent(4)) || - (src.extent(5) != dst.extent(5)) || - (src.extent(6) != dst.extent(6)) || - (src.extent(7) != dst.extent(7)) - ) { + if ((src.extent(0) != dst.extent(0)) || (src.extent(1) != dst.extent(1)) || + (src.extent(2) != dst.extent(2)) || (src.extent(3) != dst.extent(3)) || + (src.extent(4) != dst.extent(4)) || (src.extent(5) != dst.extent(5)) || + (src.extent(6) != dst.extent(6)) || (src.extent(7) != dst.extent(7))) { #ifdef KOKKOS_ENABLE_DEPRECATED_CODE exec_space.fence(); - if ( ExecCanAccessSrcDst ) { - Kokkos::Impl::ViewRemap< dst_type , src_type , ExecSpace >( dst , src ); - } - else if ( DstExecCanAccessSrc ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type >( dst , src ); - } - else if ( SrcExecCanAccessDst ) { - // Copying data between views in accessible memory spaces and either non-contiguous or incompatible shape. - Kokkos::Impl::ViewRemap< dst_type , src_type , src_execution_space >( dst , src ); - } - else { - Kokkos::Impl::throw_runtime_exception("deep_copy given views that would require a temporary allocation"); + if (ExecCanAccessSrcDst) { + Kokkos::Impl::ViewRemap(dst, src); + } else if (DstExecCanAccessSrc) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, src); + } else if (SrcExecCanAccessDst) { + // Copying data between views in accessible memory spaces and either + // non-contiguous or incompatible shape. + Kokkos::Impl::ViewRemap(dst, + src); + } else { + Kokkos::Impl::throw_runtime_exception( + "deep_copy given views that would require a temporary allocation"); } exec_space.fence(); +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif return; #else - std::string message("Deprecation Error: Kokkos::deep_copy extents of views don't match: "); - message += dst.label(); message += "("; - for(int r = 0; r::value && - ( - std::is_same< typename dst_type::array_layout , - typename src_type::array_layout >::value - || - ( dst_type::rank == 1 && - src_type::rank == 1 ) - ) && - dst.span_is_contiguous() && - src.span_is_contiguous() && - ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && - ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && - ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && - ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && - ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && - ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && - ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && - ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7())) - ) { - + // If same type, equal layout, equal dimensions, equal span, and contiguous + // memory then can byte-wise copy + + if (std::is_same::value && + (std::is_same::value || + (dst_type::rank == 1 && src_type::rank == 1)) && + dst.span_is_contiguous() && src.span_is_contiguous() && + ((dst_type::rank < 1) || (dst.stride_0() == src.stride_0())) && + ((dst_type::rank < 2) || (dst.stride_1() == src.stride_1())) && + ((dst_type::rank < 3) || (dst.stride_2() == src.stride_2())) && + ((dst_type::rank < 4) || (dst.stride_3() == src.stride_3())) && + ((dst_type::rank < 5) || (dst.stride_4() == src.stride_4())) && + ((dst_type::rank < 6) || (dst.stride_5() == src.stride_5())) && + ((dst_type::rank < 7) || (dst.stride_6() == src.stride_6())) && + ((dst_type::rank < 8) || (dst.stride_7() == src.stride_7()))) { const size_t nbytes = sizeof(typename dst_type::value_type) * dst.span(); exec_space.fence(); - if((void*)dst.data() != (void*)src.data()) { - Kokkos::Impl::DeepCopy< dst_memory_space , src_memory_space , ExecSpace > - ( exec_space , dst.data() , src.data() , nbytes ); + if ((void*)dst.data() != (void*)src.data()) { + Kokkos::Impl::DeepCopy( + exec_space, dst.data(), src.data(), nbytes); } exec_space.fence(); } else { @@ -2581,6 +2957,11 @@ void deep_copy Impl::view_copy(dst, src); exec_space.fence(); } +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endDeepCopy(); + } +#endif } } /* namespace Kokkos */ @@ -2590,90 +2971,179 @@ void deep_copy namespace Kokkos { -/** \brief Resize a view with copying old data to new data at the corresponding indices. */ -template< class T , class ... P > -inline -typename std::enable_if< - std::is_same::array_layout,Kokkos::LayoutLeft>::value || - std::is_same::array_layout,Kokkos::LayoutRight>::value ->::type -resize( Kokkos::View & v , - const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) -{ - typedef Kokkos::View view_type ; - - static_assert( Kokkos::ViewTraits::is_managed , "Can only resize managed views" ); +/** \brief Resize a view with copying old data to new data at the corresponding + * indices. */ +template +inline typename std::enable_if< + std::is_same::array_layout, + Kokkos::LayoutLeft>::value || + std::is_same::array_layout, + Kokkos::LayoutRight>::value>::type +resize(Kokkos::View& v, const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + typedef Kokkos::View view_type; + + static_assert(Kokkos::ViewTraits::is_managed, + "Can only resize managed views"); + + // Fix #904 by checking dimensions before actually resizing. + // + // Rank is known at compile time, so hopefully the compiler will + // remove branches that are compile-time false. The upcoming "if + // constexpr" language feature would make this certain. + if (view_type::Rank == 1 && n0 == static_cast(v.extent(0))) { + return; + } + if (view_type::Rank == 2 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1))) { + return; + } + if (view_type::Rank == 3 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2))) { + return; + } + if (view_type::Rank == 4 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3))) { + return; + } + if (view_type::Rank == 5 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4))) { + return; + } + if (view_type::Rank == 6 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5))) { + return; + } + if (view_type::Rank == 7 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6))) { + return; + } + if (view_type::Rank == 8 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6)) && + n7 == static_cast(v.extent(7))) { + return; + } + // If Kokkos ever supports Views of rank > 8, the above code won't + // be incorrect, because avoiding reallocation in resize() is just + // an optimization. + + // TODO (mfh 27 Jun 2017) If the old View has enough space but just + // different dimensions (e.g., if the product of the dimensions, + // including extra space for alignment, will not change), then + // consider just reusing storage. For now, Kokkos always + // reallocates if any of the dimensions change, even if the old View + // has enough space. + + view_type v_resized(v.label(), n0, n1, n2, n3, n4, n5, n6, n7); + + Kokkos::Impl::ViewRemap(v_resized, v); + + v = v_resized; +} + +/** \brief Resize a view with copying old data to new data at the corresponding + * indices. */ +template +inline typename std::enable_if< + std::is_same::array_layout, + Kokkos::LayoutLeft>::value || + std::is_same::array_layout, + Kokkos::LayoutRight>::value>::type +resize(const I& arg_prop, Kokkos::View& v, + const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + typedef Kokkos::View view_type; + + static_assert(Kokkos::ViewTraits::is_managed, + "Can only resize managed views"); // Fix #904 by checking dimensions before actually resizing. // // Rank is known at compile time, so hopefully the compiler will // remove branches that are compile-time false. The upcoming "if // constexpr" language feature would make this certain. - if (view_type::Rank == 1 && - n0 == static_cast (v.extent(0))) { + if (view_type::Rank == 1 && n0 == static_cast(v.extent(0))) { return; } - if (view_type::Rank == 2 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1))) { + if (view_type::Rank == 2 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1))) { return; } - if (view_type::Rank == 3 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2))) { + if (view_type::Rank == 3 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2))) { return; } - if (view_type::Rank == 4 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3))) { + if (view_type::Rank == 4 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3))) { return; } - if (view_type::Rank == 5 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4))) { + if (view_type::Rank == 5 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4))) { return; } - if (view_type::Rank == 6 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4)) && - n5 == static_cast (v.extent(5))) { + if (view_type::Rank == 6 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5))) { return; } - if (view_type::Rank == 7 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4)) && - n5 == static_cast (v.extent(5)) && - n6 == static_cast (v.extent(6))) { + if (view_type::Rank == 7 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6))) { return; } - if (view_type::Rank == 8 && - n0 == static_cast (v.extent(0)) && - n1 == static_cast (v.extent(1)) && - n2 == static_cast (v.extent(2)) && - n3 == static_cast (v.extent(3)) && - n4 == static_cast (v.extent(4)) && - n5 == static_cast (v.extent(5)) && - n6 == static_cast (v.extent(6)) && - n7 == static_cast (v.extent(7))) { + if (view_type::Rank == 8 && n0 == static_cast(v.extent(0)) && + n1 == static_cast(v.extent(1)) && + n2 == static_cast(v.extent(2)) && + n3 == static_cast(v.extent(3)) && + n4 == static_cast(v.extent(4)) && + n5 == static_cast(v.extent(5)) && + n6 == static_cast(v.extent(6)) && + n7 == static_cast(v.extent(7))) { return; } // If Kokkos ever supports Views of rank > 8, the above code won't @@ -2687,71 +3157,72 @@ resize( Kokkos::View & v , // reallocates if any of the dimensions change, even if the old View // has enough space. - view_type v_resized( v.label(), n0, n1, n2, n3, n4, n5, n6, n7 ); + view_type v_resized(view_alloc(v.label(), std::forward(arg_prop)), + n0, n1, n2, n3, n4, n5, n6, n7); - Kokkos::Impl::ViewRemap< view_type , view_type >( v_resized , v ); + Kokkos::Impl::ViewRemap(v_resized, v); - v = v_resized ; + v = v_resized; } -/** \brief Resize a view with copying old data to new data at the corresponding indices. */ -template< class T , class ... P > -inline -void resize( Kokkos::View & v , - const typename Kokkos::View::array_layout & layout) -{ - typedef Kokkos::View view_type ; +/** \brief Resize a view with copying old data to new data at the corresponding + * indices. */ +template +inline void resize(Kokkos::View& v, + const typename Kokkos::View::array_layout& layout) { + typedef Kokkos::View view_type; - static_assert( Kokkos::ViewTraits::is_managed , "Can only resize managed views" ); + static_assert(Kokkos::ViewTraits::is_managed, + "Can only resize managed views"); - view_type v_resized( v.label(), layout ); + view_type v_resized(v.label(), layout); - Kokkos::Impl::ViewRemap< view_type , view_type >( v_resized , v ); + Kokkos::Impl::ViewRemap(v_resized, v); - v = v_resized ; + v = v_resized; } /** \brief Resize a view with discarding old data. */ -template< class T , class ... P > -inline -typename std::enable_if< - std::is_same::array_layout,Kokkos::LayoutLeft>::value || - std::is_same::array_layout,Kokkos::LayoutRight>::value ->::type -realloc( Kokkos::View & v , - const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG , - const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG ) -{ - typedef Kokkos::View view_type ; - - static_assert( Kokkos::ViewTraits::is_managed , "Can only realloc managed views" ); +template +inline typename std::enable_if< + std::is_same::array_layout, + Kokkos::LayoutLeft>::value || + std::is_same::array_layout, + Kokkos::LayoutRight>::value>::type +realloc(Kokkos::View& v, + const size_t n0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t n7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) { + typedef Kokkos::View view_type; + + static_assert(Kokkos::ViewTraits::is_managed, + "Can only realloc managed views"); const std::string label = v.label(); - v = view_type(); // Deallocate first, if the only view to allocation - v = view_type( label, n0, n1, n2, n3, n4, n5, n6, n7 ); + v = view_type(); // Deallocate first, if the only view to allocation + v = view_type(label, n0, n1, n2, n3, n4, n5, n6, n7); } /** \brief Resize a view with discarding old data. */ -template< class T , class ... P > -inline -void realloc( Kokkos::View & v , - const typename Kokkos::View::array_layout & layout) -{ - typedef Kokkos::View view_type ; +template +inline void realloc( + Kokkos::View& v, + const typename Kokkos::View::array_layout& layout) { + typedef Kokkos::View view_type; - static_assert( Kokkos::ViewTraits::is_managed , "Can only realloc managed views" ); + static_assert(Kokkos::ViewTraits::is_managed, + "Can only realloc managed views"); const std::string label = v.label(); - v = view_type(); // Deallocate first, if the only view to allocation - v = view_type( label, layout ); + v = view_type(); // Deallocate first, if the only view to allocation + v = view_type(label, layout); } } /* namespace Kokkos */ @@ -2762,94 +3233,99 @@ namespace Kokkos { namespace Impl { // Deduce Mirror Types -template +template struct MirrorViewType { // The incoming view_type - typedef typename Kokkos::View src_view_type; + typedef typename Kokkos::View src_view_type; // The memory space for the mirror view typedef typename Space::memory_space memory_space; // Check whether it is the same memory space - enum { is_same_memspace = std::is_same::value }; + enum { + is_same_memspace = + std::is_same::value + }; // The array_layout typedef typename src_view_type::array_layout array_layout; - // The data type (we probably want it non-const since otherwise we can't even deep_copy to it. + // The data type (we probably want it non-const since otherwise we can't even + // deep_copy to it. typedef typename src_view_type::non_const_data_type data_type; // The destination view type if it is not the same memory space - typedef Kokkos::View dest_view_type; + typedef Kokkos::View dest_view_type; // If it is the same memory_space return the existsing view_type // This will also keep the unmanaged trait if necessary - typedef typename std::conditional::type view_type; + typedef typename std::conditional::type view_type; }; -template +template struct MirrorType { // The incoming view_type - typedef typename Kokkos::View src_view_type; + typedef typename Kokkos::View src_view_type; // The memory space for the mirror view typedef typename Space::memory_space memory_space; // Check whether it is the same memory space - enum { is_same_memspace = std::is_same::value }; + enum { + is_same_memspace = + std::is_same::value + }; // The array_layout typedef typename src_view_type::array_layout array_layout; - // The data type (we probably want it non-const since otherwise we can't even deep_copy to it. + // The data type (we probably want it non-const since otherwise we can't even + // deep_copy to it. typedef typename src_view_type::non_const_data_type data_type; // The destination view type if it is not the same memory space - typedef Kokkos::View view_type; + typedef Kokkos::View view_type; }; -} +} // namespace Impl + +template +inline typename Kokkos::View::HostMirror create_mirror( + const Kokkos::View& src, + typename std::enable_if< + std::is_same::specialize, void>::value && + !std::is_same::array_layout, + Kokkos::LayoutStride>::value>::type* = 0) { + typedef View src_type; + typedef typename src_type::HostMirror dst_type; -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror( const Kokkos::View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value && - ! std::is_same< typename Kokkos::ViewTraits::array_layout - , Kokkos::LayoutStride >::value - >::type * = 0 - ) -{ - typedef View src_type ; - typedef typename src_type::HostMirror dst_type ; - - return dst_type( std::string( src.label() ).append("_mirror") + return dst_type(std::string(src.label()).append("_mirror") #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - , src.extent(0) - , src.extent(1) - , src.extent(2) - , src.extent(3) - , src.extent(4) - , src.extent(5) - , src.extent(6) - , src.extent(7) ); + , + src.extent(0), src.extent(1), src.extent(2), src.extent(3), + src.extent(4), src.extent(5), src.extent(6), src.extent(7)); #else - , src.rank_dynamic > 0 ? src.extent(0): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 1 ? src.extent(1): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 2 ? src.extent(2): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 3 ? src.extent(3): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 4 ? src.extent(4): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 5 ? src.extent(5): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 6 ? src.extent(6): KOKKOS_IMPL_CTOR_DEFAULT_ARG - , src.rank_dynamic > 7 ? src.extent(7): KOKKOS_IMPL_CTOR_DEFAULT_ARG ); + , + src.rank_dynamic > 0 ? src.extent(0) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 1 ? src.extent(1) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 2 ? src.extent(2) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 3 ? src.extent(3) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 4 ? src.extent(4) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 5 ? src.extent(5) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 6 ? src.extent(6) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG, + src.rank_dynamic > 7 ? src.extent(7) + : KOKKOS_IMPL_CTOR_DEFAULT_ARG); #endif } -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror( const Kokkos::View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value && - std::is_same< typename Kokkos::ViewTraits::array_layout - , Kokkos::LayoutStride >::value - >::type * = 0 - ) -{ - typedef View src_type ; - typedef typename src_type::HostMirror dst_type ; - - Kokkos::LayoutStride layout ; +template +inline typename Kokkos::View::HostMirror create_mirror( + const Kokkos::View& src, + typename std::enable_if< + std::is_same::specialize, void>::value && + std::is_same::array_layout, + Kokkos::LayoutStride>::value>::type* = 0) { + typedef View src_type; + typedef typename src_type::HostMirror dst_type; + + Kokkos::LayoutStride layout; layout.dimension[0] = src.extent(0); layout.dimension[1] = src.extent(1); @@ -2869,117 +3345,119 @@ create_mirror( const Kokkos::View & src layout.stride[6] = src.stride_6(); layout.stride[7] = src.stride_7(); - return dst_type( std::string( src.label() ).append("_mirror") , layout ); + return dst_type(std::string(src.label()).append("_mirror"), layout); } - // Create a mirror in a new space (specialization for different space) -template -typename Impl::MirrorType::view_type -create_mirror(const Space& , const Kokkos::View & src - , typename std::enable_if< - std::is_same< typename ViewTraits::specialize , void >::value - >::type * = 0) { - return typename Impl::MirrorType::view_type(src.label(),src.layout()); +template +typename Impl::MirrorType::view_type create_mirror( + const Space&, const Kokkos::View& src, + typename std::enable_if::specialize, void>::value>::type* = 0) { + return typename Impl::MirrorType::view_type(src.label(), + src.layout()); } -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror_view( const Kokkos::View & src - , typename std::enable_if<( - std::is_same< typename Kokkos::View::memory_space - , typename Kokkos::View::HostMirror::memory_space - >::value - && - std::is_same< typename Kokkos::View::data_type - , typename Kokkos::View::HostMirror::data_type - >::value - )>::type * = 0 - ) -{ - return src ; +template +inline typename Kokkos::View::HostMirror create_mirror_view( + const Kokkos::View& src, + typename std::enable_if< + (std::is_same< + typename Kokkos::View::memory_space, + typename Kokkos::View::HostMirror::memory_space>::value && + std::is_same::data_type, + typename Kokkos::View::HostMirror::data_type>:: + value)>::type* = 0) { + return src; } -template< class T , class ... P > -inline -typename Kokkos::View::HostMirror -create_mirror_view( const Kokkos::View & src - , typename std::enable_if< ! ( - std::is_same< typename Kokkos::View::memory_space - , typename Kokkos::View::HostMirror::memory_space - >::value - && - std::is_same< typename Kokkos::View::data_type - , typename Kokkos::View::HostMirror::data_type - >::value - )>::type * = 0 - ) -{ - return Kokkos::create_mirror( src ); +template +inline typename Kokkos::View::HostMirror create_mirror_view( + const Kokkos::View& src, + typename std::enable_if::memory_space, + typename Kokkos::View::HostMirror::memory_space>::value && + std::is_same::data_type, + typename Kokkos::View::HostMirror::data_type>:: + value)>::type* = 0) { + return Kokkos::create_mirror(src); } // Create a mirror view in a new space (specialization for same space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , typename std::enable_if::is_same_memspace>::type* = 0 ) { +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + typename std::enable_if< + Impl::MirrorViewType::is_same_memspace>::type* = 0) { return src; } // Create a mirror view in a new space (specialization for different space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , typename std::enable_if::is_same_memspace>::type* = 0 ) { - return typename Impl::MirrorViewType::view_type(src.label(),src.layout()); +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + typename std::enable_if< + !Impl::MirrorViewType::is_same_memspace>::type* = 0) { + return typename Impl::MirrorViewType::view_type(src.label(), + src.layout()); } -// Create a mirror view and deep_copy in a new space (specialization for same space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view_and_copy(const Space& , const Kokkos::View & src - , std::string const& name = "" - , typename std::enable_if::is_same_memspace>::type* = 0 ) { +// Create a mirror view and deep_copy in a new space (specialization for same +// space) +template +typename Impl::MirrorViewType::view_type +create_mirror_view_and_copy( + const Space&, const Kokkos::View& src, + std::string const& name = "", + typename std::enable_if< + Impl::MirrorViewType::is_same_memspace>::type* = 0) { (void)name; return src; } -// Create a mirror view and deep_copy in a new space (specialization for different space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view_and_copy(const Space& , const Kokkos::View & src - , std::string const& name = "" - , typename std::enable_if::is_same_memspace>::type* = 0 ) { - using Mirror = typename Impl::MirrorViewType::view_type; +// Create a mirror view and deep_copy in a new space (specialization for +// different space) +template +typename Impl::MirrorViewType::view_type +create_mirror_view_and_copy( + const Space&, const Kokkos::View& src, + std::string const& name = "", + typename std::enable_if< + !Impl::MirrorViewType::is_same_memspace>::type* = 0) { + using Mirror = typename Impl::MirrorViewType::view_type; std::string label = name.empty() ? src.label() : name; auto mirror = Mirror(ViewAllocateWithoutInitializing(label), src.layout()); deep_copy(mirror, src); return mirror; } - -// Create a mirror view in a new space without initializing (specialization for same space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , Kokkos::Impl::WithoutInitializing_t - , typename std::enable_if::is_same_memspace>::type* = 0 ) { + +// Create a mirror view in a new space without initializing (specialization for +// same space) +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + Kokkos::Impl::WithoutInitializing_t, + typename std::enable_if< + Impl::MirrorViewType::is_same_memspace>::type* = 0) { return src; } - -// Create a mirror view in a new space without initializing (specialization for different space) -template -typename Impl::MirrorViewType::view_type -create_mirror_view(const Space& , const Kokkos::View & src - , Kokkos::Impl::WithoutInitializing_t - , typename std::enable_if::is_same_memspace>::type* = 0 ) { - using Mirror = typename Impl::MirrorViewType::view_type; - return Mirror(Kokkos::ViewAllocateWithoutInitializing(src.label()), src.layout()); + +// Create a mirror view in a new space without initializing (specialization for +// different space) +template +typename Impl::MirrorViewType::view_type create_mirror_view( + const Space&, const Kokkos::View& src, + Kokkos::Impl::WithoutInitializing_t, + typename std::enable_if< + !Impl::MirrorViewType::is_same_memspace>::type* = 0) { + using Mirror = typename Impl::MirrorViewType::view_type; + return Mirror(Kokkos::ViewAllocateWithoutInitializing(src.label()), + src.layout()); } } /* namespace Kokkos */ - //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/Kokkos_Core.hpp b/lib/kokkos/core/src/Kokkos_Core.hpp index 9fbba0abfa..7661efeca7 100644 --- a/lib/kokkos/core/src/Kokkos_Core.hpp +++ b/lib/kokkos/core/src/Kokkos_Core.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -49,11 +50,11 @@ #include -#if defined( KOKKOS_ENABLE_SERIAL ) +#if defined(KOKKOS_ENABLE_SERIAL) #include #endif -#if defined( KOKKOS_ENABLE_OPENMP ) +#if defined(KOKKOS_ENABLE_OPENMP) #include #endif @@ -62,23 +63,23 @@ #include //#endif -#if defined( KOKKOS_ENABLE_QTHREADS ) +#if defined(KOKKOS_ENABLE_QTHREADS) #include #endif -#if defined( KOKKOS_ENABLE_HPX ) +#if defined(KOKKOS_ENABLE_HPX) #include #endif -#if defined( KOKKOS_ENABLE_THREADS ) +#if defined(KOKKOS_ENABLE_THREADS) #include #endif -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include #endif -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) #include #endif @@ -111,18 +112,13 @@ struct InitArguments { int skip_device; bool disable_warnings; - InitArguments( int nt = -1 - , int nn = -1 - , int dv = -1 - , bool dw = false - ) - : num_threads{ nt } - , num_numa{ nn } - , device_id{ dv } - , ndevices{ -1 } - , skip_device{ 9999 } - , disable_warnings{ dw } - {} + InitArguments(int nt = -1, int nn = -1, int dv = -1, bool dw = false) + : num_threads{nt}, + num_numa{nn}, + device_id{dv}, + ndevices{-1}, + skip_device{9999}, + disable_warnings{dw} {} }; void initialize(int& narg, char* arg[]); @@ -164,9 +160,9 @@ void finalize_all(); void fence(); /** \brief Print "Bill of Materials" */ -void print_configuration( std::ostream & , const bool detail = false ); +void print_configuration(std::ostream&, const bool detail = false); -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -177,92 +173,80 @@ namespace Kokkos { * The allocation is tracked in Kokkos memory tracking system, so * leaked memory can be identified. */ -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void * kokkos_malloc( const std::string & arg_alloc_label - , const size_t arg_alloc_size ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - allocate_tracked( MemorySpace() , arg_alloc_label , arg_alloc_size ); +template +inline void* kokkos_malloc(const std::string& arg_alloc_label, + const size_t arg_alloc_size) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::allocate_tracked( + MemorySpace(), arg_alloc_label, arg_alloc_size); } -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void * kokkos_malloc( const size_t arg_alloc_size ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - allocate_tracked( MemorySpace() , "no-label" , arg_alloc_size ); +template +inline void* kokkos_malloc(const size_t arg_alloc_size) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::allocate_tracked( + MemorySpace(), "no-label", arg_alloc_size); } -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void kokkos_free( void * arg_alloc ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - deallocate_tracked( arg_alloc ); +template +inline void kokkos_free(void* arg_alloc) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::deallocate_tracked( + arg_alloc); } -template< class Space = typename Kokkos::DefaultExecutionSpace::memory_space > -inline -void * kokkos_realloc( void * arg_alloc , const size_t arg_alloc_size ) -{ - typedef typename Space::memory_space MemorySpace ; - return Impl::SharedAllocationRecord< MemorySpace >:: - reallocate_tracked( arg_alloc , arg_alloc_size ); +template +inline void* kokkos_realloc(void* arg_alloc, const size_t arg_alloc_size) { + typedef typename Space::memory_space MemorySpace; + return Impl::SharedAllocationRecord::reallocate_tracked( + arg_alloc, arg_alloc_size); } -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { /** \brief ScopeGuard - * Some user scope issues have been identified with some Kokkos::finalize calls; - * ScopeGuard aims to correct these issues. + * Some user scope issues have been identified with some Kokkos::finalize + * calls; ScopeGuard aims to correct these issues. * - * Two requirements for ScopeGuard: - * if Kokkos::is_initialized() in the constructor, don't call Kokkos::initialize or Kokkos::finalize - * it is not copyable or assignable + * Two requirements for ScopeGuard: + * if Kokkos::is_initialized() in the constructor, don't call + * Kokkos::initialize or Kokkos::finalize it is not copyable or assignable */ class ScopeGuard { -public: - ScopeGuard ( int& narg, char* arg[] ) - { - sg_init = false; - if ( ! Kokkos::is_initialized() ) { - initialize( narg, arg ); + public: + ScopeGuard(int& narg, char* arg[]) { + sg_init = false; + if (!Kokkos::is_initialized()) { + initialize(narg, arg); sg_init = true; } } - ScopeGuard ( const InitArguments& args = InitArguments() ) - { - sg_init = false; - if ( ! Kokkos::is_initialized() ) { - initialize( args ); + ScopeGuard(const InitArguments& args = InitArguments()) { + sg_init = false; + if (!Kokkos::is_initialized()) { + initialize(args); sg_init = true; } } - ~ScopeGuard( ) - { - if ( Kokkos::is_initialized() && sg_init) { - finalize(); + ~ScopeGuard() { + if (Kokkos::is_initialized() && sg_init) { + finalize(); } } -//private: - bool sg_init; - - ScopeGuard& operator=( const ScopeGuard& ) = delete; - ScopeGuard( const ScopeGuard& ) = delete; + // private: + bool sg_init; + ScopeGuard& operator=(const ScopeGuard&) = delete; + ScopeGuard(const ScopeGuard&) = delete; }; -} // namespace Kokkos +} // namespace Kokkos #include #include @@ -271,4 +255,3 @@ public: //---------------------------------------------------------------------------- #endif - diff --git a/lib/kokkos/core/src/Kokkos_Core_fwd.hpp b/lib/kokkos/core/src/Kokkos_Core_fwd.hpp index 55c6a5494a..5b89dc51ca 100644 --- a/lib/kokkos/core/src/Kokkos_Core_fwd.hpp +++ b/lib/kokkos/core/src/Kokkos_Core_fwd.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,8 +58,8 @@ //---------------------------------------------------------------------------- // Have assumed a 64bit build (8byte pointers) throughout the code base. -static_assert( sizeof(void*) == 8 - , "Kokkos assumes 64-bit build; i.e., 8-byte pointers" ); +static_assert(sizeof(void *) == 8, + "Kokkos assumes 64-bit build; i.e., 8-byte pointers"); //---------------------------------------------------------------------------- @@ -66,133 +67,137 @@ namespace Kokkos { struct AUTO_t { KOKKOS_INLINE_FUNCTION - constexpr const AUTO_t & operator()() const { return *this; } + constexpr const AUTO_t &operator()() const { return *this; } }; namespace { -/**\brief Token to indicate that a parameter's value is to be automatically selected */ +/**\brief Token to indicate that a parameter's value is to be automatically + * selected */ constexpr AUTO_t AUTO = Kokkos::AUTO_t(); -} +} // namespace struct InvalidType {}; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Forward declarations for class inter-relationships namespace Kokkos { -class HostSpace; ///< Memory space for main process and CPU execution spaces +class HostSpace; ///< Memory space for main process and CPU execution spaces class AnonymousSpace; #ifdef KOKKOS_ENABLE_HBWSPACE namespace Experimental { -class HBWSpace; /// Memory space for hbw_malloc from memkind (e.g. for KNL processor) +class HBWSpace; /// Memory space for hbw_malloc from memkind (e.g. for KNL + /// processor) } #endif -#if defined( KOKKOS_ENABLE_SERIAL ) -class Serial; ///< Execution space main process on CPU. +#if defined(KOKKOS_ENABLE_SERIAL) +class Serial; ///< Execution space main process on CPU. #endif -#if defined( KOKKOS_ENABLE_QTHREADS ) +#if defined(KOKKOS_ENABLE_QTHREADS) class Qthreads; ///< Execution space with Qthreads back-end. #endif -#if defined( KOKKOS_ENABLE_HPX ) +#if defined(KOKKOS_ENABLE_HPX) namespace Experimental { class HPX; ///< Execution space with HPX back-end. } #endif -#if defined( KOKKOS_ENABLE_THREADS ) -class Threads; ///< Execution space with pthreads back-end. +#if defined(KOKKOS_ENABLE_THREADS) +class Threads; ///< Execution space with pthreads back-end. #endif -#if defined( KOKKOS_ENABLE_OPENMP ) -class OpenMP; ///< OpenMP execution space. +#if defined(KOKKOS_ENABLE_OPENMP) +class OpenMP; ///< OpenMP execution space. #endif -#if defined( KOKKOS_ENABLE_OPENMPTARGET ) +#if defined(KOKKOS_ENABLE_OPENMPTARGET) namespace Experimental { -class OpenMPTarget; ///< OpenMPTarget execution space. +class OpenMPTarget; ///< OpenMPTarget execution space. class OpenMPTargetSpace; -} +} // namespace Experimental #endif - -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) class CudaSpace; ///< Memory space on Cuda GPU class CudaUVMSpace; ///< Memory space on Cuda GPU with UVM class CudaHostPinnedSpace; ///< Memory space on Host accessible to Cuda GPU class Cuda; ///< Execution space for Cuda GPU #endif -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) namespace Experimental { -class ROCmSpace ; ///< Memory space on ROCm GPU -class ROCm ; ///< Execution space for ROCm GPU -} +class ROCmSpace; ///< Memory space on ROCm GPU +class ROCm; ///< Execution space for ROCm GPU +} // namespace Experimental #endif -template +template struct Device; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Set the default execution space. /// Define Kokkos::DefaultExecutionSpace as per configuration option /// or chosen from the enabled execution spaces in the following order: -/// Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, Kokkos::Threads, Kokkos::Serial +/// Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, +/// Kokkos::Threads, Kokkos::Serial namespace Kokkos { -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA ) - typedef Cuda DefaultExecutionSpace; -#elif defined ( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET ) - typedef Experimental::OpenMPTarget DefaultExecutionSpace ; -#elif defined ( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM ) - typedef Experimental::ROCm DefaultExecutionSpace ; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef OpenMP DefaultExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Threads DefaultExecutionSpace; +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) +typedef Cuda DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET) +typedef Experimental::OpenMPTarget DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM) +typedef Experimental::ROCm DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) +typedef OpenMP DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) +typedef Threads DefaultExecutionSpace; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Qthreads DefaultExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) - typedef Kokkos::Experimental::HPX DefaultExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) - typedef Serial DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) +typedef Kokkos::Experimental::HPX DefaultExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) +typedef Serial DefaultExecutionSpace; #else -# error "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." +#error \ + "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::Cuda, Kokkos::Experimental::OpenMPTarget, Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." #endif -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef OpenMP DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Threads DefaultHostExecutionSpace; +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) +typedef OpenMP DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) +typedef Threads DefaultHostExecutionSpace; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Qthreads DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) - typedef Serial DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_OPENMP ) - typedef OpenMP DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_THREADS ) - typedef Threads DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) +typedef Serial DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_OPENMP) +typedef OpenMP DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_THREADS) +typedef Threads DefaultHostExecutionSpace; //#elif defined( KOKKOS_ENABLE_QTHREADS ) // typedef Qthreads DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_HPX ) - typedef Kokkos::Experimental::HPX DefaultHostExecutionSpace; -#elif defined( KOKKOS_ENABLE_SERIAL ) - typedef Serial DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_HPX) +typedef Kokkos::Experimental::HPX DefaultHostExecutionSpace; +#elif defined(KOKKOS_ENABLE_SERIAL) +typedef Serial DefaultHostExecutionSpace; #else -# error "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." +#error \ + "At least one of the following execution spaces must be defined in order to use Kokkos: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial." #endif -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- // Detect the active execution space and define its memory space. @@ -203,44 +208,44 @@ namespace Kokkos { namespace Impl { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA ) && defined( KOKKOS_ENABLE_CUDA ) -typedef Kokkos::CudaSpace ActiveExecutionMemorySpace; -#elif defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU ) -typedef Kokkos::HostSpace ActiveExecutionMemorySpace ; -#elif defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) -typedef Kokkos::HostSpace ActiveExecutionMemorySpace; +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA) && \ + defined(KOKKOS_ENABLE_CUDA) +typedef Kokkos::CudaSpace ActiveExecutionMemorySpace; +#elif defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU) +typedef Kokkos::HostSpace ActiveExecutionMemorySpace; +#elif defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) +typedef Kokkos::HostSpace ActiveExecutionMemorySpace; #else typedef void ActiveExecutionMemorySpace; #endif -template< class ActiveSpace, class MemorySpace > +template struct VerifyExecutionCanAccessMemorySpace { - enum {value = 0}; + enum { value = 0 }; }; -template< class Space > -struct VerifyExecutionCanAccessMemorySpace< Space, Space > -{ - enum {value = 1}; +template +struct VerifyExecutionCanAccessMemorySpace { + enum { value = 1 }; KOKKOS_INLINE_FUNCTION static void verify(void) {} KOKKOS_INLINE_FUNCTION static void verify(const void *) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos -#define KOKKOS_RESTRICT_EXECUTION_TO_DATA( DATA_SPACE, DATA_PTR ) \ - Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< \ - Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE >::verify( DATA_PTR ) +#define KOKKOS_RESTRICT_EXECUTION_TO_DATA(DATA_SPACE, DATA_PTR) \ + Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< \ + Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE>::verify(DATA_PTR) -#define KOKKOS_RESTRICT_EXECUTION_TO_( DATA_SPACE ) \ +#define KOKKOS_RESTRICT_EXECUTION_TO_(DATA_SPACE) \ Kokkos::Impl::VerifyExecutionCanAccessMemorySpace< \ - Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE >::verify() + Kokkos::Impl::ActiveExecutionMemorySpace, DATA_SPACE>::verify() //---------------------------------------------------------------------------- namespace Kokkos { - void fence(); +void fence(); } //---------------------------------------------------------------------------- @@ -249,29 +254,33 @@ namespace Kokkos { namespace Impl { -template< class DstSpace, class SrcSpace, class ExecutionSpace = typename DstSpace::execution_space > +template struct DeepCopy; -template +template struct ViewFillETIAvail; -template::value> +template ::value> struct ViewFill; -template +template struct ViewCopyETIAvail; -template::value> +template ::value> struct ViewCopy; -template< class Functor - , class Policy - , class EnableFunctor = void - , class EnablePolicy = void - > +template struct FunctorPolicyExecutionSpace; //---------------------------------------------------------------------------- @@ -281,18 +290,20 @@ struct FunctorPolicyExecutionSpace; /// /// This is an implementation detail of parallel_for. Users should /// skip this and go directly to the nonmember function parallel_for. -template< class FunctorType, class ExecPolicy, class ExecutionSpace = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelFor; +template ::execution_space> +class ParallelFor; /// \class ParallelReduce /// \brief Implementation detail of parallel_reduce. /// /// This is an implementation detail of parallel_reduce. Users should /// skip this and go directly to the nonmember function parallel_reduce. -template< class FunctorType, class ExecPolicy, class ReducerType = InvalidType, class ExecutionSpace = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelReduce; +template ::execution_space> +class ParallelReduce; /// \class ParallelScan /// \brief Implementation detail of parallel_scan. @@ -300,56 +311,71 @@ template< class FunctorType, class ExecPolicy, class ReducerType = InvalidType, /// This is an implementation detail of parallel_scan. Users should /// skip this and go directly to the documentation of the nonmember /// template function Kokkos::parallel_scan. -template< class FunctorType, class ExecPolicy, class ExecutionSapce = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelScan; - -template< class FunctorType, class ExecPolicy, class ReturnType = InvalidType, class ExecutionSapce = - typename Impl::FunctorPolicyExecutionSpace< FunctorType, ExecPolicy >::execution_space - > class ParallelScanWithTotal; - -} // namespace Impl - -template struct Sum; -template struct Prod; -template struct Min; -template struct Max; -template struct MinMax; -template struct MinLoc; -template struct MaxLoc; -template struct MinMaxLoc; -template struct BAnd; -template struct BOr; -template struct LAnd; -template struct LOr; - - -} // namespace Kokkos +template ::execution_space> +class ParallelScan; + +template ::execution_space> +class ParallelScanWithTotal; + +} // namespace Impl + +template +struct Sum; +template +struct Prod; +template +struct Min; +template +struct Max; +template +struct MinMax; +template +struct MinLoc; +template +struct MaxLoc; +template +struct MinMaxLoc; +template +struct BAnd; +template +struct BOr; +template +struct LAnd; +template +struct LOr; + +} // namespace Kokkos #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -namespace Kokkos{ - template struct MinMaxScalar; - template struct MinMaxLocScalar; - template struct ValLocScalar; - - namespace Experimental { - using Kokkos::Sum; - using Kokkos::Prod; - using Kokkos::Min; - using Kokkos::Max; - using Kokkos::MinMax; - using Kokkos::MinLoc; - using Kokkos::MaxLoc; - using Kokkos::MinMaxLoc; - using Kokkos::BAnd; - using Kokkos::BOr; - using Kokkos::LAnd; - using Kokkos::LOr; - using Kokkos::MinMaxScalar; - using Kokkos::MinMaxLocScalar; - using Kokkos::ValLocScalar; - } -} +namespace Kokkos { +template +struct MinMaxScalar; +template +struct MinMaxLocScalar; +template +struct ValLocScalar; + +namespace Experimental { +using Kokkos::BAnd; +using Kokkos::BOr; +using Kokkos::LAnd; +using Kokkos::LOr; +using Kokkos::Max; +using Kokkos::MaxLoc; +using Kokkos::Min; +using Kokkos::MinLoc; +using Kokkos::MinMax; +using Kokkos::MinMaxLoc; +using Kokkos::MinMaxLocScalar; +using Kokkos::MinMaxScalar; +using Kokkos::Prod; +using Kokkos::Sum; +using Kokkos::ValLocScalar; +} // namespace Experimental +} // namespace Kokkos #endif #endif /* #ifndef KOKKOS_CORE_FWD_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Crs.hpp b/lib/kokkos/core/src/Kokkos_Crs.hpp index 8412ced921..f57863263b 100644 --- a/lib/kokkos/core/src/Kokkos_Crs.hpp +++ b/lib/kokkos/core/src/Kokkos_Crs.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -76,26 +77,27 @@ namespace Kokkos { ///

  • entries( entry , i2 , i3 , ... );
  • ///
  • entries( row_map[i0] + i1 , i2 , i3 , ... );
  • /// -template< class DataType, - class Arg1Type, - class Arg2Type = void, - typename SizeType = typename ViewTraits::size_type> +template ::size_type> class Crs { -protected: + protected: typedef ViewTraits traits; -public: - typedef DataType data_type; - typedef typename traits::array_layout array_layout; - typedef typename traits::execution_space execution_space; - typedef typename traits::memory_space memory_space; - typedef typename traits::device_type device_type; - typedef SizeType size_type; - - typedef Crs< DataType , Arg1Type , Arg2Type , SizeType > staticcrsgraph_type; - typedef Crs< DataType , array_layout , typename traits::host_mirror_space , SizeType > HostMirror; - typedef View row_map_type; - typedef View entries_type; + public: + typedef DataType data_type; + typedef typename traits::array_layout array_layout; + typedef typename traits::execution_space execution_space; + typedef typename traits::memory_space memory_space; + typedef typename traits::device_type device_type; + typedef SizeType size_type; + + typedef Crs staticcrsgraph_type; + typedef Crs + HostMirror; + typedef View row_map_type; + typedef View entries_type; row_map_type row_map; entries_type entries; @@ -103,62 +105,49 @@ public: /* * Default Constructors, operators and destructor */ - KOKKOS_FUNCTION Crs() = default; - KOKKOS_FUNCTION Crs(Crs const &) = default; - KOKKOS_FUNCTION Crs(Crs &&) = default; - KOKKOS_FUNCTION Crs& operator=(Crs const &) = default; - KOKKOS_FUNCTION Crs& operator=(Crs &&) = default; - KOKKOS_FUNCTION ~Crs() = default; + KOKKOS_FUNCTION Crs() = default; + KOKKOS_FUNCTION Crs(Crs const&) = default; + KOKKOS_FUNCTION Crs(Crs&&) = default; + KOKKOS_FUNCTION Crs& operator=(Crs const&) = default; + KOKKOS_FUNCTION Crs& operator=(Crs&&) = default; + KOKKOS_FUNCTION ~Crs() = default; /** \brief Assign to a view of the rhs array. * If the old view is the last view * then allocated memory is deallocated. */ - template - KOKKOS_INLINE_FUNCTION - Crs(const RowMapType& row_map_, const EntriesType& entries_) - : row_map(row_map_), entries(entries_) - { - } + template + KOKKOS_INLINE_FUNCTION Crs(const RowMapType& row_map_, + const EntriesType& entries_) + : row_map(row_map_), entries(entries_) {} /** \brief Return number of rows in the graph */ KOKKOS_INLINE_FUNCTION size_type numRows() const { - return (row_map.extent(0) != 0) ? - row_map.extent(0) - static_cast (1) : - static_cast (0); + return (row_map.extent(0) != 0) + ? row_map.extent(0) - static_cast(1) + : static_cast(0); } }; /*--------------------------------------------------------------------------*/ -template< class OutCounts, - class DataType, - class Arg1Type, - class Arg2Type, +template void get_crs_transpose_counts( - OutCounts& out, - Crs const& in, + OutCounts& out, Crs const& in, std::string const& name = "transpose_counts"); -template< class OutCounts, - class InCrs> +template typename OutCounts::value_type get_crs_row_map_from_counts( - OutCounts& out, - InCrs const& in, - std::string const& name = "row_map"); + OutCounts& out, InCrs const& in, std::string const& name = "row_map"); -template< class DataType, - class Arg1Type, - class Arg2Type, - class SizeType> -void transpose_crs( - Crs& out, - Crs const& in); +template +void transpose_crs(Crs& out, + Crs const& in); -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -171,21 +160,22 @@ template class GetCrsTransposeCounts { public: using execution_space = typename InCrs::execution_space; - using self_type = GetCrsTransposeCounts; - using index_type = typename InCrs::size_type; + using self_type = GetCrsTransposeCounts; + using index_type = typename InCrs::size_type; + private: InCrs in; OutCounts out; + public: KOKKOS_INLINE_FUNCTION - void operator()(index_type i) const { - atomic_increment( &out[in.entries(i)] ); - } - GetCrsTransposeCounts(InCrs const& arg_in, OutCounts const& arg_out): - in(arg_in),out(arg_out) { - using policy_type = RangePolicy; + void operator()(index_type i) const { atomic_increment(&out[in.entries(i)]); } + GetCrsTransposeCounts(InCrs const& arg_in, OutCounts const& arg_out) + : in(arg_in), out(arg_out) { + using policy_type = RangePolicy; using closure_type = Kokkos::Impl::ParallelFor; - const closure_type closure(*this, policy_type(0, index_type(in.entries.size()))); + const closure_type closure(*this, + policy_type(0, index_type(in.entries.size()))); closure.execute(); execution_space().fence(); } @@ -195,13 +185,15 @@ template class CrsRowMapFromCounts { public: using execution_space = typename InCounts::execution_space; - using value_type = typename OutRowMap::value_type; - using index_type = typename InCounts::size_type; + using value_type = typename OutRowMap::value_type; + using index_type = typename InCounts::size_type; using last_value_type = Kokkos::View; + private: InCounts m_in; OutRowMap m_out; last_value_type m_last_value; + public: KOKKOS_INLINE_FUNCTION void operator()(index_type i, value_type& update, bool final_pass) const { @@ -209,22 +201,22 @@ class CrsRowMapFromCounts { update += m_in(i); if (final_pass) m_out(i + 1) = update; } else if (final_pass) { - m_out(0) = 0; + m_out(0) = 0; m_last_value() = update; } } KOKKOS_INLINE_FUNCTION void init(value_type& update) const { update = 0; } KOKKOS_INLINE_FUNCTION - void join(volatile value_type& update, const volatile value_type& input) const { + void join(volatile value_type& update, + const volatile value_type& input) const { update += input; } using self_type = CrsRowMapFromCounts; - CrsRowMapFromCounts(InCounts const& arg_in, OutRowMap const& arg_out): - m_in(arg_in), m_out(arg_out), m_last_value("last_value") { - } + CrsRowMapFromCounts(InCounts const& arg_in, OutRowMap const& arg_out) + : m_in(arg_in), m_out(arg_out), m_last_value("last_value") {} value_type execute() { - using policy_type = RangePolicy; + using policy_type = RangePolicy; using closure_type = Kokkos::Impl::ParallelScan; closure_type closure(*this, policy_type(0, m_in.size() + 1)); closure.execute(); @@ -238,31 +230,32 @@ template class FillCrsTransposeEntries { public: using execution_space = typename InCrs::execution_space; - using memory_space = typename InCrs::memory_space; - using value_type = typename OutCrs::entries_type::value_type; - using index_type = typename InCrs::size_type; + using memory_space = typename InCrs::memory_space; + using value_type = typename OutCrs::entries_type::value_type; + using index_type = typename InCrs::size_type; + private: using counters_type = View; InCrs in; OutCrs out; counters_type counters; + public: KOKKOS_INLINE_FUNCTION void operator()(index_type i) const { auto begin = in.row_map(i); - auto end = in.row_map(i + 1); + auto end = in.row_map(i + 1); for (auto j = begin; j < end; ++j) { - auto ti = in.entries(j); - auto tbegin = out.row_map(ti); - auto tj = atomic_fetch_add( &counters(ti), 1 ); - out.entries( tbegin + tj ) = i; + auto ti = in.entries(j); + auto tbegin = out.row_map(ti); + auto tj = atomic_fetch_add(&counters(ti), 1); + out.entries(tbegin + tj) = i; } } using self_type = FillCrsTransposeEntries; - FillCrsTransposeEntries(InCrs const& arg_in, OutCrs const& arg_out): - in(arg_in),out(arg_out), - counters("counters", arg_out.numRows()) { - using policy_type = RangePolicy; + FillCrsTransposeEntries(InCrs const& arg_in, OutCrs const& arg_out) + : in(arg_in), out(arg_out), counters("counters", arg_out.numRows()) { + using policy_type = RangePolicy; using closure_type = Kokkos::Impl::ParallelFor; const closure_type closure(*this, policy_type(0, index_type(in.numRows()))); closure.execute(); @@ -270,7 +263,8 @@ class FillCrsTransposeEntries { } }; -}} // namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -278,66 +272,51 @@ class FillCrsTransposeEntries { namespace Kokkos { -template< class OutCounts, - class DataType, - class Arg1Type, - class Arg2Type, +template void get_crs_transpose_counts( - OutCounts& out, - Crs const& in, + OutCounts& out, Crs const& in, std::string const& name) { using InCrs = Crs; - out = OutCounts(name, in.numRows()); + out = OutCounts(name, in.numRows()); Kokkos::Impl::GetCrsTransposeCounts functor(in, out); } -template< class OutRowMap, - class InCounts> +template typename OutRowMap::value_type get_crs_row_map_from_counts( - OutRowMap& out, - InCounts const& in, - std::string const& name) { + OutRowMap& out, InCounts const& in, std::string const& name) { out = OutRowMap(ViewAllocateWithoutInitializing(name), in.size() + 1); Kokkos::Impl::CrsRowMapFromCounts functor(in, out); return functor.execute(); } -template< class DataType, - class Arg1Type, - class Arg2Type, - class SizeType> -void transpose_crs( - Crs& out, - Crs const& in) -{ - typedef Crs crs_type ; - typedef typename crs_type::memory_space memory_space ; - typedef View counts_type ; +template +void transpose_crs(Crs& out, + Crs const& in) { + typedef Crs crs_type; + typedef typename crs_type::memory_space memory_space; + typedef View counts_type; { - counts_type counts; - Kokkos::get_crs_transpose_counts(counts, in); - Kokkos::get_crs_row_map_from_counts(out.row_map, counts, - "tranpose_row_map"); + counts_type counts; + Kokkos::get_crs_transpose_counts(counts, in); + Kokkos::get_crs_row_map_from_counts(out.row_map, counts, + "tranpose_row_map"); } out.entries = decltype(out.entries)("transpose_entries", in.entries.size()); - Kokkos::Impl:: - FillCrsTransposeEntries entries_functor(in, out); + Kokkos::Impl::FillCrsTransposeEntries entries_functor( + in, out); } -template< class CrsType, - class Functor, +template struct CountAndFillBase; -template< class CrsType, - class Functor, - class ExecutionSpace> +template struct CountAndFillBase { - using data_type = typename CrsType::size_type; - using size_type = typename CrsType::size_type; + using data_type = typename CrsType::size_type; + using size_type = typename CrsType::size_type; using row_map_type = typename CrsType::row_map_type; - using counts_type = row_map_type; + using counts_type = row_map_type; CrsType m_crs; Functor m_functor; counts_type m_counts; @@ -348,30 +327,26 @@ struct CountAndFillBase { struct Fill {}; inline void operator()(Fill, size_type i) const { auto j = m_crs.row_map(i); - /* we don't want to access entries(entries.size()), even if its just to get its - address and never use it. - this can happen when row (i) is empty and all rows after it are also empty. - we could compare to row_map(i + 1), but that is a read from global memory, - whereas dimension_0() should be part of the View in registers (or constant memory) */ - data_type* fill = - (j == static_cast(m_crs.entries.extent(0))) ? - nullptr : (&(m_crs.entries(j))); + /* we don't want to access entries(entries.size()), even if its just to get + its address and never use it. this can happen when row (i) is empty and + all rows after it are also empty. we could compare to row_map(i + 1), but + that is a read from global memory, whereas dimension_0() should be part + of the View in registers (or constant memory) */ + data_type* fill = (j == static_cast(m_crs.entries.extent(0))) + ? nullptr + : (&(m_crs.entries(j))); m_functor(i, fill); } - CountAndFillBase(CrsType& crs, Functor const& f): - m_crs(crs), - m_functor(f) - {} + CountAndFillBase(CrsType& crs, Functor const& f) : m_crs(crs), m_functor(f) {} }; -#if defined( KOKKOS_ENABLE_CUDA ) -template< class CrsType, - class Functor> +#if defined(KOKKOS_ENABLE_CUDA) +template struct CountAndFillBase { - using data_type = typename CrsType::size_type; - using size_type = typename CrsType::size_type; + using data_type = typename CrsType::size_type; + using size_type = typename CrsType::size_type; using row_map_type = typename CrsType::row_map_type; - using counts_type = row_map_type; + using counts_type = row_map_type; CrsType m_crs; Functor m_functor; counts_type m_counts; @@ -382,70 +357,62 @@ struct CountAndFillBase { struct Fill {}; __device__ inline void operator()(Fill, size_type i) const { auto j = m_crs.row_map(i); - /* we don't want to access entries(entries.size()), even if its just to get its - address and never use it. - this can happen when row (i) is empty and all rows after it are also empty. - we could compare to row_map(i + 1), but that is a read from global memory, - whereas dimension_0() should be part of the View in registers (or constant memory) */ - data_type* fill = - (j == static_cast(m_crs.entries.extent(0))) ? - nullptr : (&(m_crs.entries(j))); + /* we don't want to access entries(entries.size()), even if its just to get + its address and never use it. this can happen when row (i) is empty and + all rows after it are also empty. we could compare to row_map(i + 1), but + that is a read from global memory, whereas dimension_0() should be part + of the View in registers (or constant memory) */ + data_type* fill = (j == static_cast(m_crs.entries.extent(0))) + ? nullptr + : (&(m_crs.entries(j))); m_functor(i, fill); } - CountAndFillBase(CrsType& crs, Functor const& f): - m_crs(crs), - m_functor(f) - {} + CountAndFillBase(CrsType& crs, Functor const& f) : m_crs(crs), m_functor(f) {} }; #endif -template< class CrsType, - class Functor> +template struct CountAndFill : public CountAndFillBase { using base_type = CountAndFillBase; - using typename base_type::data_type; - using typename base_type::size_type; - using typename base_type::counts_type; using typename base_type::Count; + using typename base_type::counts_type; + using typename base_type::data_type; using typename base_type::Fill; + using typename base_type::size_type; using entries_type = typename CrsType::entries_type; - using self_type = CountAndFill; - CountAndFill(CrsType& crs, size_type nrows, Functor const& f): - base_type(crs, f) - { + using self_type = CountAndFill; + CountAndFill(CrsType& crs, size_type nrows, Functor const& f) + : base_type(crs, f) { using execution_space = typename CrsType::execution_space; - this->m_counts = counts_type("counts", nrows); + this->m_counts = counts_type("counts", nrows); { - using count_policy_type = RangePolicy; - using count_closure_type = - Kokkos::Impl::ParallelFor; - const count_closure_type closure(*this, count_policy_type(0, nrows)); - closure.execute(); + using count_policy_type = RangePolicy; + using count_closure_type = + Kokkos::Impl::ParallelFor; + const count_closure_type closure(*this, count_policy_type(0, nrows)); + closure.execute(); } - auto nentries = Kokkos:: - get_crs_row_map_from_counts(this->m_crs.row_map, this->m_counts); + auto nentries = Kokkos::get_crs_row_map_from_counts(this->m_crs.row_map, + this->m_counts); this->m_counts = counts_type(); this->m_crs.entries = entries_type("entries", nentries); { - using fill_policy_type = RangePolicy; - using fill_closure_type = - Kokkos::Impl::ParallelFor; - const fill_closure_type closure(*this, fill_policy_type(0, nrows)); - closure.execute(); + using fill_policy_type = RangePolicy; + using fill_closure_type = + Kokkos::Impl::ParallelFor; + const fill_closure_type closure(*this, fill_policy_type(0, nrows)); + closure.execute(); } crs = this->m_crs; } }; -template< class CrsType, - class Functor> -void count_and_fill_crs( - CrsType& crs, - typename CrsType::size_type nrows, - Functor const& f) { +template +void count_and_fill_crs(CrsType& crs, typename CrsType::size_type nrows, + Functor const& f) { Kokkos::CountAndFill(crs, nrows, f); } -} // namespace Kokkos +} // namespace Kokkos #endif /* #define KOKKOS_CRS_HPP */ diff --git a/lib/kokkos/core/src/Kokkos_Cuda.hpp b/lib/kokkos/core/src/Kokkos_Cuda.hpp index 4eb8ab4d4b..ad62ecf383 100644 --- a/lib/kokkos/core/src/Kokkos_Cuda.hpp +++ b/lib/kokkos/core/src/Kokkos_Cuda.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDA_HPP #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include @@ -62,37 +63,45 @@ #include #include - /*--------------------------------------------------------------------------*/ namespace Kokkos { namespace Impl { -class CudaExec ; -class CudaInternal ; -} // namespace Impl -} // namespace Kokkos +class CudaExec; +class CudaInternal; +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ namespace Kokkos { namespace Impl { - namespace Experimental { - enum class CudaLaunchMechanism:unsigned{Default=0,ConstantMemory=1,GlobalMemory=2,LocalMemory=4}; - - constexpr inline CudaLaunchMechanism operator | (CudaLaunchMechanism p1, CudaLaunchMechanism p2) { - return static_cast(static_cast(p1) | static_cast(p2)); - } - constexpr inline CudaLaunchMechanism operator & (CudaLaunchMechanism p1, CudaLaunchMechanism p2) { - return static_cast(static_cast(p1) & static_cast(p2)); - } - - template - struct CudaDispatchProperties { - CudaLaunchMechanism launch_mechanism = l; - }; - } +namespace Experimental { +enum class CudaLaunchMechanism : unsigned { + Default = 0, + ConstantMemory = 1, + GlobalMemory = 2, + LocalMemory = 4 +}; + +constexpr inline CudaLaunchMechanism operator|(CudaLaunchMechanism p1, + CudaLaunchMechanism p2) { + return static_cast(static_cast(p1) | + static_cast(p2)); } +constexpr inline CudaLaunchMechanism operator&(CudaLaunchMechanism p1, + CudaLaunchMechanism p2) { + return static_cast(static_cast(p1) & + static_cast(p2)); +} + +template +struct CudaDispatchProperties { + CudaLaunchMechanism launch_mechanism = l; +}; +} // namespace Experimental +} // namespace Impl /// \class Cuda /// \brief Kokkos Execution Space that uses CUDA to run on GPUs. /// @@ -104,32 +113,32 @@ namespace Impl { /// sequentially. The Cuda execution space uses NVIDIA's CUDA programming /// model to execute kernels in parallel on GPUs. class Cuda { -public: + public: //! \name Type declarations that all Kokkos execution spaces must provide. //@{ //! Tag this class as a kokkos execution space - typedef Cuda execution_space ; + typedef Cuda execution_space; -#if defined( KOKKOS_ENABLE_CUDA_UVM ) +#if defined(KOKKOS_ENABLE_CUDA_UVM) //! This execution space's preferred memory space. - typedef CudaUVMSpace memory_space ; + typedef CudaUVMSpace memory_space; #else //! This execution space's preferred memory space. - typedef CudaSpace memory_space ; + typedef CudaSpace memory_space; #endif //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; //! The size_type best suited for this execution space. - typedef memory_space::size_type size_type ; + typedef memory_space::size_type size_type; //! This execution space's preferred array layout. - typedef LayoutLeft array_layout ; + typedef LayoutLeft array_layout; //! - typedef ScratchMemorySpace< Cuda > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; //@} //-------------------------------------------------- @@ -139,7 +148,7 @@ public: /// \brief True if and only if this method is being called in a /// thread-parallel function. KOKKOS_INLINE_FUNCTION static int in_parallel() { -#if defined( __CUDA_ARCH__ ) +#if defined(__CUDA_ARCH__) return true; #else return false; @@ -174,17 +183,17 @@ public: /// device have completed. static void impl_static_fence(); - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence(); - #else +#else void fence() const; - #endif +#endif /** \brief Return the maximum amount of concurrency. */ static int concurrency(); //! Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); //@} //-------------------------------------------------- @@ -195,10 +204,10 @@ public: Cuda(); - Cuda( Cuda && ) = default ; - Cuda( const Cuda & ) = default ; - Cuda & operator = ( Cuda && ) = default ; - Cuda & operator = ( const Cuda & ) = default ; + Cuda(Cuda&&) = default; + Cuda(const Cuda&) = default; + Cuda& operator=(Cuda&&) = default; + Cuda& operator=(const Cuda&) = default; Cuda(cudaStream_t stream); @@ -207,9 +216,9 @@ public: //@{ struct SelectDevice { - int cuda_device_id ; + int cuda_device_id; SelectDevice() : cuda_device_id(0) {} - explicit SelectDevice( int id ) : cuda_device_id( id ) {} + explicit SelectDevice(int id) : cuda_device_id(id) {} }; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE @@ -220,8 +229,8 @@ public: static int is_initialized(); //! Initialize, telling the CUDA run-time library which device to use. - static void initialize( const SelectDevice = SelectDevice() - , const size_t num_instances = 1 ); + static void initialize(const SelectDevice = SelectDevice(), + const size_t num_instances = 1); #else //! Free any resources being consumed by the device. static void impl_finalize(); @@ -230,8 +239,8 @@ public: static int impl_is_initialized(); //! Initialize, telling the CUDA run-time library which device to use. - static void impl_initialize( const SelectDevice = SelectDevice() - , const size_t num_instances = 1 ); + static void impl_initialize(const SelectDevice = SelectDevice(), + const size_t num_instances = 1); #endif /// \brief Cuda device architecture of the selected device. @@ -248,20 +257,22 @@ public: static std::vector detect_device_arch(); cudaStream_t cuda_stream() const; - int cuda_device() const; + int cuda_device() const; //@} //-------------------------------------------------------------------------- static const char* name(); - inline Impl::CudaInternal* impl_internal_space_instance() const { return m_space_instance; } -private: + inline Impl::CudaInternal* impl_internal_space_instance() const { + return m_space_instance; + } + private: Impl::CudaInternal* m_space_instance; }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -269,18 +280,15 @@ private: namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::CudaSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -#if defined( KOKKOS_ENABLE_CUDA_UVM ) +#if defined(KOKKOS_ENABLE_CUDA_UVM) // If forcing use of UVM everywhere // then must assume that CudaUVMSpace @@ -288,44 +296,34 @@ struct MemorySpaceAccess // This will fail when a strange host-side execution space // that defines CudaUVMSpace as its preferredmemory space. -template<> -struct MemorySpaceAccess - < Kokkos::CudaUVMSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; #endif - -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::CudaSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::HostSpace - , Kokkos::Cuda::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - inline static void verify( void ) { CudaSpace::access_error(); } - inline static void verify( const void * p ) { CudaSpace::access_error(p); } + inline static void verify(void) { CudaSpace::access_error(); } + inline static void verify(const void* p) { CudaSpace::access_error(p); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -343,4 +341,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #ifndef KOKKOS_CUDA_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_CudaSpace.hpp b/lib/kokkos/core/src/Kokkos_CudaSpace.hpp index 4b32811bfc..a320aea2f8 100644 --- a/lib/kokkos/core/src/Kokkos_CudaSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_CudaSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_CUDASPACE_HPP #include -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include @@ -57,6 +58,11 @@ #include +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST +extern "C" bool kokkos_impl_cuda_pin_uvm_to_host(); +extern "C" void kokkos_impl_cuda_set_pin_uvm_to_host(bool); +#endif + /*--------------------------------------------------------------------------*/ namespace Kokkos { @@ -64,30 +70,28 @@ namespace Kokkos { /** \brief Cuda on-device memory management */ class CudaSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef CudaSpace memory_space ; - typedef Kokkos::Cuda execution_space ; - typedef Kokkos::Device device_type; + typedef CudaSpace memory_space; + typedef Kokkos::Cuda execution_space; + typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef unsigned int size_type; /*--------------------------------*/ CudaSpace(); - CudaSpace( CudaSpace && rhs ) = default ; - CudaSpace( const CudaSpace & rhs ) = default ; - CudaSpace & operator = ( CudaSpace && rhs ) = default ; - CudaSpace & operator = ( const CudaSpace & rhs ) = default ; - ~CudaSpace() = default ; + CudaSpace(CudaSpace&& rhs) = default; + CudaSpace(const CudaSpace& rhs) = default; + CudaSpace& operator=(CudaSpace&& rhs) = default; + CudaSpace& operator=(const CudaSpace& rhs) = default; + ~CudaSpace() = default; /**\brief Allocate untracked memory in the cuda space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the cuda space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } @@ -95,14 +99,13 @@ public: /*--------------------------------*/ /** \brief Error reporting for HostSpace attempt to access CudaSpace */ static void access_error(); - static void access_error( const void * const ); - -private: + static void access_error(const void* const); - int m_device ; ///< Which Cuda device + private: + int m_device; ///< Which Cuda device static constexpr const char* m_name = "Cuda"; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::CudaSpace , void > ; + friend class Kokkos::Impl::SharedAllocationRecord; }; namespace Impl { @@ -123,10 +126,11 @@ void init_lock_arrays_cuda_space(); /// If the array is not yet allocated it will do so. int* atomic_lock_array_cuda_space_ptr(bool deallocate = false); -/// \brief Retrieve the pointer to the scratch array for team and thread private global memory. +/// \brief Retrieve the pointer to the scratch array for team and thread private +/// global memory. /// /// Team and Thread private scratch allocations in -/// global memory are acquired via locks. +/// global memory are aquired via locks. /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* scratch_lock_array_cuda_space_ptr(bool deallocate = false); @@ -138,8 +142,8 @@ int* scratch_lock_array_cuda_space_ptr(bool deallocate = false); /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* threadid_lock_array_cuda_space_ptr(bool deallocate = false); -} -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -150,54 +154,56 @@ namespace Kokkos { * through Cuda's unified virtual memory (UVM) runtime. */ class CudaUVMSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef CudaUVMSpace memory_space ; - typedef Cuda execution_space ; - typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef CudaUVMSpace memory_space; + typedef Cuda execution_space; + typedef Kokkos::Device device_type; + typedef unsigned int size_type; /** \brief If UVM capability is available */ static bool available(); - /*--------------------------------*/ /** \brief CudaUVMSpace specific routine */ static int number_of_allocations(); /*--------------------------------*/ - /*--------------------------------*/ CudaUVMSpace(); - CudaUVMSpace( CudaUVMSpace && rhs ) = default ; - CudaUVMSpace( const CudaUVMSpace & rhs ) = default ; - CudaUVMSpace & operator = ( CudaUVMSpace && rhs ) = default ; - CudaUVMSpace & operator = ( const CudaUVMSpace & rhs ) = default ; - ~CudaUVMSpace() = default ; + CudaUVMSpace(CudaUVMSpace&& rhs) = default; + CudaUVMSpace(const CudaUVMSpace& rhs) = default; + CudaUVMSpace& operator=(CudaUVMSpace&& rhs) = default; + CudaUVMSpace& operator=(const CudaUVMSpace& rhs) = default; + ~CudaUVMSpace() = default; /**\brief Allocate untracked memory in the cuda space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the cuda space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST + static bool cuda_pin_uvm_to_host(); + static void cuda_set_pin_uvm_to_host(bool val); +#endif /*--------------------------------*/ -private: - int m_device ; ///< Which Cuda device + private: + int m_device; ///< Which Cuda device +#ifdef KOKKOS_IMPL_DEBUG_CUDA_PIN_UVM_TO_HOST + static bool kokkos_impl_cuda_pin_uvm_to_host_v; +#endif static constexpr const char* m_name = "CudaUVM"; - }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -208,42 +214,39 @@ namespace Kokkos { * through Cuda's host-pinned memory allocation. */ class CudaHostPinnedSpace { -public: - + public: //! Tag this class as a kokkos memory space /** \brief Memory is in HostSpace so use the HostSpace::execution_space */ - typedef HostSpace::execution_space execution_space ; - typedef CudaHostPinnedSpace memory_space ; - typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef HostSpace::execution_space execution_space; + typedef CudaHostPinnedSpace memory_space; + typedef Kokkos::Device device_type; + typedef unsigned int size_type; /*--------------------------------*/ CudaHostPinnedSpace(); - CudaHostPinnedSpace( CudaHostPinnedSpace && rhs ) = default ; - CudaHostPinnedSpace( const CudaHostPinnedSpace & rhs ) = default ; - CudaHostPinnedSpace & operator = ( CudaHostPinnedSpace && rhs ) = default ; - CudaHostPinnedSpace & operator = ( const CudaHostPinnedSpace & rhs ) = default ; - ~CudaHostPinnedSpace() = default ; + CudaHostPinnedSpace(CudaHostPinnedSpace&& rhs) = default; + CudaHostPinnedSpace(const CudaHostPinnedSpace& rhs) = default; + CudaHostPinnedSpace& operator=(CudaHostPinnedSpace&& rhs) = default; + CudaHostPinnedSpace& operator=(const CudaHostPinnedSpace& rhs) = default; + ~CudaHostPinnedSpace() = default; /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } -private: - + private: static constexpr const char* m_name = "CudaHostPinned"; /*--------------------------------*/ }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -251,119 +254,126 @@ private: namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::CudaSpace >::assignable , "" ); -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::CudaUVMSpace >::assignable , "" ); -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaHostPinnedSpace >::assignable , "" ); +static_assert(Kokkos::Impl::MemorySpaceAccess::assignable, + ""); +static_assert(Kokkos::Impl::MemorySpaceAccess::assignable, + ""); +static_assert( + Kokkos::Impl::MemorySpaceAccess::assignable, + ""); //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::CudaSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::CudaUVMSpace > { +template <> +struct MemorySpaceAccess { // HostSpace::execution_space != CudaUVMSpace::execution_space enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::CudaHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // HostSpace::execution_space == CudaHostPinnedSpace::execution_space enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::CudaUVMSpace > { +template <> +struct MemorySpaceAccess { // CudaSpace::execution_space == CudaUVMSpace::execution_space enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaSpace , Kokkos::CudaHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // CudaSpace::execution_space != CudaHostPinnedSpace::execution_space enum { assignable = false }; - enum { accessible = true }; // CudaSpace::execution_space - enum { deepcopy = true }; + enum { accessible = true }; // CudaSpace::execution_space + enum { deepcopy = true }; }; //---------------------------------------- // CudaUVMSpace::execution_space == Cuda // CudaUVMSpace accessible to both Cuda and Host -template<> -struct MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; - enum { accessible = false }; // Cuda cannot access HostSpace - enum { deepcopy = true }; + enum { accessible = false }; // Cuda cannot access HostSpace + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::CudaSpace > { +template <> +struct MemorySpaceAccess { // CudaUVMSpace::execution_space == CudaSpace::execution_space // Can access CudaUVMSpace from Host but cannot access CudaSpace from Host enum { assignable = false }; // CudaUVMSpace::execution_space can access CudaSpace enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaUVMSpace , Kokkos::CudaHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // CudaUVMSpace::execution_space != CudaHostPinnedSpace::execution_space enum { assignable = false }; - enum { accessible = true }; // CudaUVMSpace::execution_space - enum { deepcopy = true }; + enum { accessible = true }; // CudaUVMSpace::execution_space + enum { deepcopy = true }; }; - //---------------------------------------- // CudaHostPinnedSpace::execution_space == HostSpace::execution_space // CudaHostPinnedSpace accessible to both Cuda and Host -template<> -struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::HostSpace > { - enum { assignable = false }; // Cannot access from Cuda - enum { accessible = true }; // CudaHostPinnedSpace::execution_space - enum { deepcopy = true }; +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from Cuda + enum { accessible = true }; // CudaHostPinnedSpace::execution_space + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaSpace > { - enum { assignable = false }; // Cannot access from Host +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from Host enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaUVMSpace > { - enum { assignable = false }; // different execution_space - enum { accessible = true }; // same accessibility - enum { deepcopy = true }; +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // different execution_space + enum { accessible = true }; // same accessibility + enum { deepcopy = true }; }; //---------------------------------------- -}} // namespace Kokkos::Impl +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -371,247 +381,223 @@ struct MemorySpaceAccess< Kokkos::CudaHostPinnedSpace , Kokkos::CudaUVMSpace > { namespace Kokkos { namespace Impl { -void DeepCopyAsyncCuda( void * dst , const void * src , size_t n); +void DeepCopyAsyncCuda(void* dst, const void* src, size_t n); -template<> struct DeepCopy< CudaSpace , CudaSpace , Cuda> -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Cuda & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Cuda&, void* dst, const void* src, size_t); }; -template<> struct DeepCopy< CudaSpace , HostSpace , Cuda > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Cuda & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Cuda&, void* dst, const void* src, size_t); }; -template<> struct DeepCopy< HostSpace , CudaSpace , Cuda > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Cuda & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Cuda&, void* dst, const void* src, size_t); }; -template struct DeepCopy< CudaSpace , CudaSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda>( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< HostSpace , CudaSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaSpace , CudaUVMSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaSpace , CudaHostPinnedSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } -template -struct DeepCopy< CudaUVMSpace , CudaSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaUVMSpace , CudaUVMSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template -struct DeepCopy< CudaUVMSpace , CudaHostPinnedSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaUVMSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< CudaSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } -template struct DeepCopy< CudaHostPinnedSpace , CudaSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaHostPinnedSpace , CudaUVMSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaHostPinnedSpace , CudaHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< CudaHostPinnedSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } -template struct DeepCopy< HostSpace , CudaUVMSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , CudaSpace , Cuda >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -template struct DeepCopy< HostSpace , CudaHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , HostSpace , Cuda >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopyAsyncCuda (dst,src,n); + DeepCopyAsyncCuda(dst, src, n); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -620,79 +606,83 @@ namespace Kokkos { namespace Impl { /** Running in CudaSpace attempting to access HostSpace: error */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::CudaSpace , Kokkos::HostSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("Cuda code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("Cuda code attempted to access HostSpace memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("Cuda code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("Cuda code attempted to access HostSpace memory"); + } }; /** Running in CudaSpace accessing CudaUVMSpace: ok */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::CudaSpace , Kokkos::CudaUVMSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; /** Running in CudaSpace accessing CudaHostPinnedSpace: ok */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::CudaSpace , Kokkos::CudaHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; /** Running in CudaSpace attempting to access an unknown space: error */ -template< class OtherSpace > +template struct VerifyExecutionCanAccessMemorySpace< - typename enable_if< ! is_same::value , Kokkos::CudaSpace >::type , - OtherSpace > -{ + typename enable_if::value, + Kokkos::CudaSpace>::type, + OtherSpace> { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("Cuda code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("Cuda code attempted to access unknown Space memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("Cuda code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("Cuda code attempted to access unknown Space memory"); + } }; //---------------------------------------------------------------------------- /** Running in HostSpace attempting to access CudaSpace */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - inline static void verify( void ) { CudaSpace::access_error(); } - inline static void verify( const void * p ) { CudaSpace::access_error(p); } + inline static void verify(void) { CudaSpace::access_error(); } + inline static void verify(const void* p) { CudaSpace::access_error(p); } }; /** Running in HostSpace accessing CudaUVMSpace is OK */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaUVMSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; /** Running in HostSpace accessing CudaHostPinnedSpace is OK */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) {} - KOKKOS_INLINE_FUNCTION static void verify( const void * ) {} + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -700,248 +690,214 @@ struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::CudaHost namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::CudaSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: - - friend class SharedAllocationRecord< Kokkos::CudaUVMSpace , void > ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + friend class SharedAllocationRecord; - typedef SharedAllocationRecord< void , void > RecordBase ; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); - static ::cudaTextureObject_t - attach_texture_object( const unsigned sizeof_alias - , void * const alloc_ptr - , const size_t alloc_size ); + static ::cudaTextureObject_t attach_texture_object( + const unsigned sizeof_alias, void* const alloc_ptr, + const size_t alloc_size); #ifdef KOKKOS_DEBUG - static RecordBase s_root_record ; + static RecordBase s_root_record; #endif - ::cudaTextureObject_t m_tex_obj ; - const Kokkos::CudaSpace m_space ; - -protected: + ::cudaTextureObject_t m_tex_obj; + const Kokkos::CudaSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_tex_obj(0), m_space() {} - SharedAllocationRecord( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); - -public: + SharedAllocationRecord( + const Kokkos::CudaSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); - std::string get_label() const ; + public: + std::string get_label() const; - static SharedAllocationRecord * allocate( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static SharedAllocationRecord* allocate(const Kokkos::CudaSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::CudaSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::CudaSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); - - template< typename AliasType > - inline - ::cudaTextureObject_t attach_texture_object() - { - static_assert( ( std::is_same< AliasType , int >::value || - std::is_same< AliasType , ::int2 >::value || - std::is_same< AliasType , ::int4 >::value ) - , "Cuda texture fetch only supported for alias types of int, ::int2, or ::int4" ); - - if ( m_tex_obj == 0 ) { - m_tex_obj = attach_texture_object( sizeof(AliasType) - , (void*) RecordBase::m_alloc_ptr - , RecordBase::m_alloc_size ); - } - - return m_tex_obj ; + static void deallocate_tracked(void* const arg_alloc_ptr); + + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); + + template + inline ::cudaTextureObject_t attach_texture_object() { + static_assert((std::is_same::value || + std::is_same::value || + std::is_same::value), + "Cuda texture fetch only supported for alias types of int, " + "::int2, or ::int4"); + + if (m_tex_obj == 0) { + m_tex_obj = attach_texture_object(sizeof(AliasType), + (void*)RecordBase::m_alloc_ptr, + RecordBase::m_alloc_size); } - template< typename AliasType > - inline - int attach_texture_object_offset( const AliasType * const ptr ) - { - // Texture object is attached to the entire allocation range - return ptr - reinterpret_cast( RecordBase::m_alloc_ptr ); - } - - static void print_records( std::ostream & , const Kokkos::CudaSpace & , bool detail = false ); -}; - + return m_tex_obj; + } -template<> -class SharedAllocationRecord< Kokkos::CudaUVMSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: + template + inline int attach_texture_object_offset(const AliasType* const ptr) { + // Texture object is attached to the entire allocation range + return ptr - reinterpret_cast(RecordBase::m_alloc_ptr); + } - typedef SharedAllocationRecord< void , void > RecordBase ; + static void print_records(std::ostream&, const Kokkos::CudaSpace&, + bool detail = false); +}; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; - static void deallocate( RecordBase * ); + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static RecordBase s_root_record ; + static void deallocate(RecordBase*); - ::cudaTextureObject_t m_tex_obj ; - const Kokkos::CudaUVMSpace m_space ; + static RecordBase s_root_record; -protected: + ::cudaTextureObject_t m_tex_obj; + const Kokkos::CudaUVMSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_tex_obj(0), m_space() {} - SharedAllocationRecord( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::CudaUVMSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: + public: + std::string get_label() const; - std::string get_label() const ; - - static SharedAllocationRecord * allocate( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + static SharedAllocationRecord* allocate(const Kokkos::CudaUVMSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::CudaUVMSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::CudaUVMSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); - - - template< typename AliasType > - inline - ::cudaTextureObject_t attach_texture_object() - { - static_assert( ( std::is_same< AliasType , int >::value || - std::is_same< AliasType , ::int2 >::value || - std::is_same< AliasType , ::int4 >::value ) - , "Cuda texture fetch only supported for alias types of int, ::int2, or ::int4" ); - - if ( m_tex_obj == 0 ) { - m_tex_obj = SharedAllocationRecord< Kokkos::CudaSpace , void >:: - attach_texture_object( sizeof(AliasType) - , (void*) RecordBase::m_alloc_ptr - , RecordBase::m_alloc_size ); - } - - return m_tex_obj ; - } - - template< typename AliasType > - inline - int attach_texture_object_offset( const AliasType * const ptr ) - { - // Texture object is attached to the entire allocation range - return ptr - reinterpret_cast( RecordBase::m_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); + + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); + + template + inline ::cudaTextureObject_t attach_texture_object() { + static_assert((std::is_same::value || + std::is_same::value || + std::is_same::value), + "Cuda texture fetch only supported for alias types of int, " + "::int2, or ::int4"); + + if (m_tex_obj == 0) { + m_tex_obj = SharedAllocationRecord:: + attach_texture_object(sizeof(AliasType), + (void*)RecordBase::m_alloc_ptr, + RecordBase::m_alloc_size); } - static void print_records( std::ostream & , const Kokkos::CudaUVMSpace & , bool detail = false ); -}; + return m_tex_obj; + } -template<> -class SharedAllocationRecord< Kokkos::CudaHostPinnedSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: + template + inline int attach_texture_object_offset(const AliasType* const ptr) { + // Texture object is attached to the entire allocation range + return ptr - reinterpret_cast(RecordBase::m_alloc_ptr); + } - typedef SharedAllocationRecord< void , void > RecordBase ; + static void print_records(std::ostream&, const Kokkos::CudaUVMSpace&, + bool detail = false); +}; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; - static void deallocate( RecordBase * ); + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static RecordBase s_root_record ; + static void deallocate(RecordBase*); - const Kokkos::CudaHostPinnedSpace m_space ; + static RecordBase s_root_record; -protected: + const Kokkos::CudaHostPinnedSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_space() {} - SharedAllocationRecord( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::CudaHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: + public: + std::string get_label() const; - std::string get_label() const ; - - static SharedAllocationRecord * allocate( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + static SharedAllocationRecord* allocate( + const Kokkos::CudaHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::CudaHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::CudaHostPinnedSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream & , const Kokkos::CudaHostPinnedSpace & , bool detail = false ); + static void print_records(std::ostream&, const Kokkos::CudaHostPinnedSpace&, + bool detail = false); }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_CUDA ) */ #endif /* #define KOKKOS_CUDASPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp b/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp index 5c85850fda..bf3a134b64 100644 --- a/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp +++ b/lib/kokkos/core/src/Kokkos_ExecPolicy.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -53,7 +54,7 @@ #include #if defined(KOKKOS_ENABLE_PROFILING) #include -#endif // KOKKOS_ENABLE_PROFILING +#endif // KOKKOS_ENABLE_PROFILING //---------------------------------------------------------------------------- @@ -65,7 +66,7 @@ struct ParallelReduceTag {}; struct ChunkSize { int value; - ChunkSize(int value_):value(value_) {} + ChunkSize(int value_) : value(value_) {} }; /** \brief Execution policy for work over a range of an integral type. @@ -89,210 +90,192 @@ struct ChunkSize { * * Blocking is the granularity of partitioning the range among threads. */ -template -class RangePolicy - : public Impl::PolicyTraits -{ -public: - typedef Impl::PolicyTraits traits; -private: - - typename traits::execution_space m_space ; - typename traits::index_type m_begin ; - typename traits::index_type m_end ; - typename traits::index_type m_granularity ; - typename traits::index_type m_granularity_mask ; - - template +template +class RangePolicy : public Impl::PolicyTraits { + public: + typedef Impl::PolicyTraits traits; + + private: + typename traits::execution_space m_space; + typename traits::index_type m_begin; + typename traits::index_type m_end; + typename traits::index_type m_granularity; + typename traits::index_type m_granularity_mask; + + template friend class RangePolicy; -public: + public: //! Tag this class as an execution policy typedef RangePolicy execution_policy; - typedef typename traits::index_type member_type ; + typedef typename traits::index_type member_type; typedef typename traits::index_type index_type; - KOKKOS_INLINE_FUNCTION const typename traits::execution_space & space() const { return m_space ; } - KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin ; } - KOKKOS_INLINE_FUNCTION member_type end() const { return m_end ; } - - //TODO: find a better workaround for Clangs weird instantiation order - // This thing is here because of an instantiation error, where the RangePolicy is inserted into FunctorValue Traits, which - // tries decltype on the operator. It tries to do this even though the first argument of parallel for clearly doesn't match. + KOKKOS_INLINE_FUNCTION const typename traits::execution_space& space() const { + return m_space; + } + KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin; } + KOKKOS_INLINE_FUNCTION member_type end() const { return m_end; } + + // TODO: find a better workaround for Clangs weird instantiation order + // This thing is here because of an instantiation error, where the RangePolicy + // is inserted into FunctorValue Traits, which tries decltype on the operator. + // It tries to do this even though the first argument of parallel for clearly + // doesn't match. void operator()(const int&) const {} RangePolicy(const RangePolicy&) = default; - RangePolicy(RangePolicy&&) = default; + RangePolicy(RangePolicy&&) = default; - template + template RangePolicy(const RangePolicy p) { - m_space = p.m_space; - m_begin = p.m_begin; - m_end = p.m_end; - m_granularity = p.m_granularity; + m_space = p.m_space; + m_begin = p.m_begin; + m_end = p.m_end; + m_granularity = p.m_granularity; m_granularity_mask = p.m_granularity_mask; } inline RangePolicy() : m_space(), m_begin(0), m_end(0) {} /** \brief Total range */ - inline - RangePolicy( const typename traits::execution_space & work_space - , const member_type work_begin - , const member_type work_end - ) - : m_space( work_space ) - , m_begin( work_begin < work_end ? work_begin : 0 ) - , m_end( work_begin < work_end ? work_end : 0 ) - , m_granularity(0) - , m_granularity_mask(0) - { - set_auto_chunk_size(); - } + inline RangePolicy(const typename traits::execution_space& work_space, + const member_type work_begin, const member_type work_end) + : m_space(work_space), + m_begin(work_begin < work_end ? work_begin : 0), + m_end(work_begin < work_end ? work_end : 0), + m_granularity(0), + m_granularity_mask(0) { + set_auto_chunk_size(); + } /** \brief Total range */ - inline - RangePolicy( const member_type work_begin - , const member_type work_end - ) - : RangePolicy( typename traits::execution_space() - , work_begin , work_end ) - { - set_auto_chunk_size(); - } + inline RangePolicy(const member_type work_begin, const member_type work_end) + : RangePolicy(typename traits::execution_space(), work_begin, work_end) { + set_auto_chunk_size(); + } /** \brief Total range */ - template - inline - RangePolicy( const typename traits::execution_space & work_space - , const member_type work_begin - , const member_type work_end - , Args ... args - ) - : m_space( work_space ) - , m_begin( work_begin < work_end ? work_begin : 0 ) - , m_end( work_begin < work_end ? work_end : 0 ) - , m_granularity(0) - , m_granularity_mask(0) - { - set_auto_chunk_size(); - set(args...); - } + template + inline RangePolicy(const typename traits::execution_space& work_space, + const member_type work_begin, const member_type work_end, + Args... args) + : m_space(work_space), + m_begin(work_begin < work_end ? work_begin : 0), + m_end(work_begin < work_end ? work_end : 0), + m_granularity(0), + m_granularity_mask(0) { + set_auto_chunk_size(); + set(args...); + } /** \brief Total range */ - template - inline - RangePolicy( const member_type work_begin - , const member_type work_end - , Args ... args - ) - : RangePolicy( typename traits::execution_space() - , work_begin , work_end ) - { - set_auto_chunk_size(); - set(args...); - } + template + inline RangePolicy(const member_type work_begin, const member_type work_end, + Args... args) + : RangePolicy(typename traits::execution_space(), work_begin, work_end) { + set_auto_chunk_size(); + set(args...); + } -private: + private: inline void set() {} -public: - template - inline void set(Args ...) { - static_assert( 0 == sizeof...(Args), "Kokkos::RangePolicy: unhandled constructor arguments encountered."); + public: + template + inline void set(Args...) { + static_assert( + 0 == sizeof...(Args), + "Kokkos::RangePolicy: unhandled constructor arguments encountered."); } - template - inline void set(const ChunkSize& chunksize, Args ... args) { - m_granularity = chunksize.value; + template + inline void set(const ChunkSize& chunksize, Args... args) { + m_granularity = chunksize.value; m_granularity_mask = m_granularity - 1; } -public: + public: /** \brief return chunk_size */ - inline member_type chunk_size() const { - return m_granularity; - } + inline member_type chunk_size() const { return m_granularity; } /** \brief set chunk_size to a discrete value*/ inline RangePolicy set_chunk_size(int chunk_size_) const { - RangePolicy p = *this; - p.m_granularity = chunk_size_; + RangePolicy p = *this; + p.m_granularity = chunk_size_; p.m_granularity_mask = p.m_granularity - 1; return p; } -private: + private: /** \brief finalize chunk_size if it was set to AUTO*/ inline void set_auto_chunk_size() { + typename traits::index_type concurrency = + traits::execution_space::concurrency(); + if (concurrency == 0) concurrency = 1; - typename traits::index_type concurrency = traits::execution_space::concurrency(); - if( concurrency==0 ) concurrency=1; - - if(m_granularity > 0) { - if(!Impl::is_integral_power_of_two( m_granularity )) - Kokkos::abort("RangePolicy blocking granularity must be power of two" ); - } + if (m_granularity > 0) { + if (!Impl::is_integral_power_of_two(m_granularity)) + Kokkos::abort("RangePolicy blocking granularity must be power of two"); + } - member_type new_chunk_size = 1; - while(new_chunk_size*100*concurrency < m_end-m_begin) - new_chunk_size *= 2; - if(new_chunk_size < 128) { - new_chunk_size = 1; - while( (new_chunk_size*40*concurrency < m_end-m_begin ) && (new_chunk_size<128) ) - new_chunk_size*=2; - } - m_granularity = new_chunk_size; - m_granularity_mask = m_granularity - 1; + member_type new_chunk_size = 1; + while (new_chunk_size * 100 * concurrency < m_end - m_begin) + new_chunk_size *= 2; + if (new_chunk_size < 128) { + new_chunk_size = 1; + while ((new_chunk_size * 40 * concurrency < m_end - m_begin) && + (new_chunk_size < 128)) + new_chunk_size *= 2; + } + m_granularity = new_chunk_size; + m_granularity_mask = m_granularity - 1; } -public: + public: /** \brief Subrange for a partition's rank and size. * * Typically used to partition a range over a group of threads. */ struct WorkRange { - typedef typename RangePolicy::work_tag work_tag ; - typedef typename RangePolicy::member_type member_type ; + typedef typename RangePolicy::work_tag work_tag; + typedef typename RangePolicy::member_type member_type; - KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin ; } - KOKKOS_INLINE_FUNCTION member_type end() const { return m_end ; } + KOKKOS_INLINE_FUNCTION member_type begin() const { return m_begin; } + KOKKOS_INLINE_FUNCTION member_type end() const { return m_end; } /** \brief Subrange for a partition's rank and size. * * Typically used to partition a range over a group of threads. */ KOKKOS_INLINE_FUNCTION - WorkRange( const RangePolicy & range - , const int part_rank - , const int part_size - ) - : m_begin(0), m_end(0) - { - if ( part_size ) { - - // Split evenly among partitions, then round up to the granularity. - const member_type work_part = - ( ( ( ( range.end() - range.begin() ) + ( part_size - 1 ) ) / part_size ) - + range.m_granularity_mask ) & ~member_type(range.m_granularity_mask); - - m_begin = range.begin() + work_part * part_rank ; - m_end = m_begin + work_part ; - - if ( range.end() < m_begin ) m_begin = range.end() ; - if ( range.end() < m_end ) m_end = range.end() ; - } + WorkRange(const RangePolicy& range, const int part_rank, + const int part_size) + : m_begin(0), m_end(0) { + if (part_size) { + // Split evenly among partitions, then round up to the granularity. + const member_type work_part = + ((((range.end() - range.begin()) + (part_size - 1)) / part_size) + + range.m_granularity_mask) & + ~member_type(range.m_granularity_mask); + + m_begin = range.begin() + work_part * part_rank; + m_end = m_begin + work_part; + + if (range.end() < m_begin) m_begin = range.end(); + if (range.end() < m_end) m_end = range.end(); } + } - private: - member_type m_begin ; - member_type m_end ; + private: + member_type m_begin; + member_type m_end; WorkRange(); - WorkRange & operator = ( const WorkRange & ); + WorkRange& operator=(const WorkRange&); }; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -301,13 +284,12 @@ namespace Kokkos { namespace Impl { -template< class ExecSpace, class ... Properties> -class TeamPolicyInternal: public Impl::PolicyTraits { -private: - typedef Impl::PolicyTraits traits; +template +class TeamPolicyInternal : public Impl::PolicyTraits { + private: + typedef Impl::PolicyTraits traits; -public: - + public: typedef typename traits::index_type index_type; //---------------------------------------- @@ -321,8 +303,8 @@ public: * With multi-operator functors it cannot be determined * which operator will be called. */ - template< class FunctorType > - static int team_size_max( const FunctorType & ); + template + static int team_size_max(const FunctorType&); /** \brief Query recommended team size for a given functor. * @@ -334,48 +316,56 @@ public: * With multi-operator functors it cannot be determined * which operator will be called. */ - template< class FunctorType > - static int team_size_recommended( const FunctorType & ); + template + static int team_size_recommended(const FunctorType&); - template< class FunctorType > - static int team_size_recommended( const FunctorType & , const int&); + template + static int team_size_recommended(const FunctorType&, const int&); - template - int team_size_recommended( const FunctorType & functor , const int vector_length); + template + int team_size_recommended(const FunctorType& functor, + const int vector_length); //---------------------------------------- /** \brief Construct policy with the given instance of the execution space */ - TeamPolicyInternal( const typename traits::execution_space & , int league_size_request , int team_size_request , int vector_length_request = 1 ); + TeamPolicyInternal(const typename traits::execution_space&, + int league_size_request, int team_size_request, + int vector_length_request = 1); - TeamPolicyInternal( const typename traits::execution_space & , int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ); + TeamPolicyInternal(const typename traits::execution_space&, + int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1); - /** \brief Construct policy with the default instance of the execution space */ - TeamPolicyInternal( int league_size_request , int team_size_request , int vector_length_request = 1 ); + /** \brief Construct policy with the default instance of the execution space + */ + TeamPolicyInternal(int league_size_request, int team_size_request, + int vector_length_request = 1); - TeamPolicyInternal( int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ); + TeamPolicyInternal(int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1); -/* TeamPolicyInternal( int league_size_request , int team_size_request ); + /* TeamPolicyInternal( int league_size_request , int team_size_request ); - TeamPolicyInternal( int league_size_request , const Kokkos::AUTO_t & );*/ + TeamPolicyInternal( int league_size_request , const Kokkos::AUTO_t & );*/ /** \brief The actual league size (number of teams) of the policy. * * This may be smaller than the requested league size due to limitations * of the execution space. */ - KOKKOS_INLINE_FUNCTION int league_size() const ; + KOKKOS_INLINE_FUNCTION int league_size() const; /** \brief The actual team size (number of threads per team) of the policy. * * This may be smaller than the requested team size due to limitations * of the execution space. */ - KOKKOS_INLINE_FUNCTION int team_size() const ; + KOKKOS_INLINE_FUNCTION int team_size() const; - inline typename traits::index_type chunk_size() const ; + inline typename traits::index_type chunk_size() const; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - inline TeamPolicyInternal set_chunk_size(int chunk_size) const ; + inline TeamPolicyInternal set_chunk_size(int chunk_size) const; #else inline TeamPolicyInternal& set_chunk_size(int chunk_size); #endif @@ -384,39 +374,38 @@ public: * each member of the execution policy. */ struct member_type { - /** \brief Handle to the currently executing team shared scratch memory */ KOKKOS_INLINE_FUNCTION - typename traits::execution_space::scratch_memory_space team_shmem() const ; + typename traits::execution_space::scratch_memory_space team_shmem() const; /** \brief Rank of this team within the league of teams */ - KOKKOS_INLINE_FUNCTION int league_rank() const ; + KOKKOS_INLINE_FUNCTION int league_rank() const; /** \brief Number of teams in the league */ - KOKKOS_INLINE_FUNCTION int league_size() const ; + KOKKOS_INLINE_FUNCTION int league_size() const; /** \brief Rank of this thread within this team */ - KOKKOS_INLINE_FUNCTION int team_rank() const ; + KOKKOS_INLINE_FUNCTION int team_rank() const; /** \brief Number of threads in this team */ - KOKKOS_INLINE_FUNCTION int team_size() const ; + KOKKOS_INLINE_FUNCTION int team_size() const; /** \brief Barrier among the threads of this team */ - KOKKOS_INLINE_FUNCTION void team_barrier() const ; + KOKKOS_INLINE_FUNCTION void team_barrier() const; - /** \brief Intra-team reduction. Returns join of all values of the team members. */ - template< class JoinOp > - KOKKOS_INLINE_FUNCTION - typename JoinOp::value_type team_reduce( const typename JoinOp::value_type - , const JoinOp & ) const ; + /** \brief Intra-team reduction. Returns join of all values of the team + * members. */ + template + KOKKOS_INLINE_FUNCTION typename JoinOp::value_type team_reduce( + const typename JoinOp::value_type, const JoinOp&) const; /** \brief Intra-team exclusive prefix sum with team_rank() ordering. * * The highest rank thread can compute the reduction total as * reduction_total = dev.team_scan( value ) + value ; */ - template< typename Type > - KOKKOS_INLINE_FUNCTION Type team_scan( const Type & value ) const ; + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value) const; /** \brief Intra-team exclusive prefix sum with team_rank() ordering * with intra-team non-deterministic ordering accumulation. @@ -427,44 +416,52 @@ public: * As such the base value for each team's scan operation is similarly * non-deterministic. */ - template< typename Type > - KOKKOS_INLINE_FUNCTION Type team_scan( const Type & value , Type * const global_accum ) const ; + template + KOKKOS_INLINE_FUNCTION Type team_scan(const Type& value, + Type* const global_accum) const; }; }; +struct PerTeamValue { + int value; + PerTeamValue(int arg); +}; - struct PerTeamValue { - int value; - PerTeamValue(int arg); - }; - - struct PerThreadValue { - int value; - PerThreadValue(int arg); - }; - - template - struct ExtractVectorLength { - static inline iType value(typename std::enable_if::value,iType>::type val, Args...) { - return val; - } - static inline typename std::enable_if::value,int>::type value(typename std::enable_if::value,iType>::type, Args...) { - return 1; - } - }; +struct PerThreadValue { + int value; + PerThreadValue(int arg); +}; - template - inline typename std::enable_if::value,iType>::type extract_vector_length(iType val, Args...) { +template +struct ExtractVectorLength { + static inline iType value( + typename std::enable_if::value, iType>::type val, + Args...) { return val; } - - template - inline typename std::enable_if::value,int>::type extract_vector_length(iType, Args...) { + static inline + typename std::enable_if::value, int>::type + value( + typename std::enable_if::value, iType>::type, + Args...) { return 1; } +}; + +template +inline typename std::enable_if::value, iType>::type +extract_vector_length(iType val, Args...) { + return val; +} +template +inline typename std::enable_if::value, int>::type +extract_vector_length(iType, Args...) { + return 1; } +} // namespace Impl + Impl::PerTeamValue PerTeam(const int& arg); Impl::PerThreadValue PerThread(const int& arg); @@ -474,38 +471,41 @@ struct ScratchRequest { int per_team; int per_thread; - inline - ScratchRequest(const int& level_, const Impl::PerTeamValue& team_value) { - level = level_; - per_team = team_value.value; + inline ScratchRequest(const int& level_, + const Impl::PerTeamValue& team_value) { + level = level_; + per_team = team_value.value; per_thread = 0; } - inline - ScratchRequest(const int& level_, const Impl::PerThreadValue& thread_value) { - level = level_; - per_team = 0; - per_thread = thread_value.value;; + inline ScratchRequest(const int& level_, + const Impl::PerThreadValue& thread_value) { + level = level_; + per_team = 0; + per_thread = thread_value.value; + ; } - inline - ScratchRequest(const int& level_, const Impl::PerTeamValue& team_value, const Impl::PerThreadValue& thread_value) { - level = level_; - per_team = team_value.value; - per_thread = thread_value.value;; + inline ScratchRequest(const int& level_, const Impl::PerTeamValue& team_value, + const Impl::PerThreadValue& thread_value) { + level = level_; + per_team = team_value.value; + per_thread = thread_value.value; + ; } - inline - ScratchRequest(const int& level_, const Impl::PerThreadValue& thread_value, const Impl::PerTeamValue& team_value) { - level = level_; - per_team = team_value.value; - per_thread = thread_value.value;; + inline ScratchRequest(const int& level_, + const Impl::PerThreadValue& thread_value, + const Impl::PerTeamValue& team_value) { + level = level_; + per_team = team_value.value; + per_thread = thread_value.value; + ; } - }; - -/** \brief Execution policy for parallel work over a league of teams of threads. +/** \brief Execution policy for parallel work over a league of teams of + * threads. * * The work functor is called for each thread of each team such that * the team's member threads are guaranteed to be concurrent. @@ -522,162 +522,197 @@ struct ScratchRequest { * be omitted. * * Possible Template arguments and their default values: - * ExecutionSpace (DefaultExecutionSpace): where to execute code. Must be enabled. - * WorkTag (none): Tag which is used as the first argument for the functor operator. - * Schedule (Schedule): Scheduling Policy (Dynamic, or Static). - * IndexType (IndexType: Integer Index type used to iterate over the Index space. + * ExecutionSpace (DefaultExecutionSpace): where to execute code. Must be + * enabled. WorkTag (none): Tag which is used as the first argument for the + * functor operator. Schedule (Schedule): Scheduling Policy + * (Dynamic, or Static). IndexType (IndexType: + * Integer Index type used to iterate over the Index space. * LaunchBounds Launch Bounds for CUDA compilation, * default of LaunchBounds<0,0> indicates no launch bounds specified. */ -template< class ... Properties> -class TeamPolicy: public - Impl::TeamPolicyInternal< - typename Impl::PolicyTraits::execution_space, - Properties ...> { +template +class TeamPolicy + : public Impl::TeamPolicyInternal< + typename Impl::PolicyTraits::execution_space, + Properties...> { typedef Impl::TeamPolicyInternal< - typename Impl::PolicyTraits::execution_space, - Properties ...> internal_policy; + typename Impl::PolicyTraits::execution_space, + Properties...> + internal_policy; - template + template friend class TeamPolicy; -public: - typedef Impl::PolicyTraits traits; + public: + typedef Impl::PolicyTraits traits; typedef TeamPolicy execution_policy; - TeamPolicy& operator = (const TeamPolicy&) = default; + TeamPolicy& operator=(const TeamPolicy&) = default; /** \brief Construct policy with the given instance of the execution space */ - TeamPolicy( const typename traits::execution_space & space_ , int league_size_request , int team_size_request , int vector_length_request = 1 ) - : internal_policy(space_,league_size_request,team_size_request, vector_length_request) {first_arg = false;} + TeamPolicy(const typename traits::execution_space& space_, + int league_size_request, int team_size_request, + int vector_length_request = 1) + : internal_policy(space_, league_size_request, team_size_request, + vector_length_request) { + first_arg = false; + } - TeamPolicy( const typename traits::execution_space & space_, int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ) - : internal_policy(space_,league_size_request,Kokkos::AUTO(), vector_length_request) {first_arg = false;} + TeamPolicy(const typename traits::execution_space& space_, + int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1) + : internal_policy(space_, league_size_request, Kokkos::AUTO(), + vector_length_request) { + first_arg = false; + } - /** \brief Construct policy with the default instance of the execution space */ - TeamPolicy( int league_size_request , int team_size_request , int vector_length_request = 1 ) - : internal_policy(league_size_request,team_size_request, vector_length_request) {first_arg = false;} + /** \brief Construct policy with the default instance of the execution space + */ + TeamPolicy(int league_size_request, int team_size_request, + int vector_length_request = 1) + : internal_policy(league_size_request, team_size_request, + vector_length_request) { + first_arg = false; + } - TeamPolicy( int league_size_request , const Kokkos::AUTO_t & , int vector_length_request = 1 ) - : internal_policy(league_size_request,Kokkos::AUTO(), vector_length_request) {first_arg = false;} + TeamPolicy(int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request = 1) + : internal_policy(league_size_request, Kokkos::AUTO(), + vector_length_request) { + first_arg = false; + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief Construct policy with the given instance of the execution space */ - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , int team_size_request , int vector_length_request, - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,team_size_request, vector_length_request) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + int team_size_request, int vector_length_request, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + team_size_request, vector_length_request) { first_arg = false; set(args...); } - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , const Kokkos::AUTO_t & , int vector_length_request , - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,Kokkos::AUTO(), vector_length_request) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + const Kokkos::AUTO_t&, int vector_length_request, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + Kokkos::AUTO(), vector_length_request) { first_arg = false; set(args...); } - /** \brief Construct policy with the default instance of the execution space */ - template - TeamPolicy( int league_size_request , int team_size_request , int vector_length_request , - Args ... args) - : internal_policy(league_size_request,team_size_request, vector_length_request) { + /** \brief Construct policy with the default instance of the execution space + */ + template + TeamPolicy(int league_size_request, int team_size_request, + int vector_length_request, Args... args) + : internal_policy(league_size_request, team_size_request, + vector_length_request) { first_arg = false; set(args...); } - template - TeamPolicy( int league_size_request , const Kokkos::AUTO_t & , int vector_length_request , - Args ... args) - : internal_policy(league_size_request,Kokkos::AUTO(), vector_length_request) { + template + TeamPolicy(int league_size_request, const Kokkos::AUTO_t&, + int vector_length_request, Args... args) + : internal_policy(league_size_request, Kokkos::AUTO(), + vector_length_request) { first_arg = false; set(args...); } /** \brief Construct policy with the given instance of the execution space */ - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , int team_size_request , - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,team_size_request, - Kokkos::Impl::extract_vector_length(args...)) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + int team_size_request, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + team_size_request, + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } - template - TeamPolicy( const typename traits::execution_space & , int league_size_request , const Kokkos::AUTO_t & , - Args ... args) - : internal_policy(typename traits::execution_space(),league_size_request,Kokkos::AUTO(), - Kokkos::Impl::extract_vector_length(args...)) { + template + TeamPolicy(const typename traits::execution_space&, int league_size_request, + const Kokkos::AUTO_t&, Args... args) + : internal_policy(typename traits::execution_space(), league_size_request, + Kokkos::AUTO(), + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } - /** \brief Construct policy with the default instance of the execution space */ - template - TeamPolicy( int league_size_request , int team_size_request , - Args ... args) - : internal_policy(league_size_request,team_size_request, - Kokkos::Impl::extract_vector_length(args...)) { + /** \brief Construct policy with the default instance of the execution space + */ + template + TeamPolicy(int league_size_request, int team_size_request, Args... args) + : internal_policy(league_size_request, team_size_request, + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } - template - TeamPolicy( int league_size_request , const Kokkos::AUTO_t & , - Args ... args) - : internal_policy(league_size_request,Kokkos::AUTO(), - Kokkos::Impl::extract_vector_length(args...)) { + template + TeamPolicy(int league_size_request, const Kokkos::AUTO_t&, Args... args) + : internal_policy(league_size_request, Kokkos::AUTO(), + Kokkos::Impl::extract_vector_length(args...)) { first_arg = true; set(args...); } #endif - template - TeamPolicy(const TeamPolicy p):internal_policy(p) { + template + TeamPolicy(const TeamPolicy p) : internal_policy(p) { first_arg = p.first_arg; } -private: + private: bool first_arg; - TeamPolicy(const internal_policy& p):internal_policy(p) {first_arg = false;} + TeamPolicy(const internal_policy& p) : internal_policy(p) { + first_arg = false; + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE inline void set() {} #endif -public: + public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template - inline void set(Args ...) { - static_assert( 0 == sizeof...(Args), "Kokkos::TeamPolicy: unhandled constructor arguments encountered."); + template + inline void set(Args...) { + static_assert( + 0 == sizeof...(Args), + "Kokkos::TeamPolicy: unhandled constructor arguments encountered."); } - template - inline typename std::enable_if::value>::type set(iType, Args ... args) { - if(first_arg) { + template + inline typename std::enable_if::value>::type set( + iType, Args... args) { + if (first_arg) { first_arg = false; set(args...); } else { first_arg = false; - Kokkos::Impl::throw_runtime_exception("Kokkos::TeamPolicy: integer argument to constructor in illegal place."); + Kokkos::Impl::throw_runtime_exception( + "Kokkos::TeamPolicy: integer argument to constructor in illegal " + "place."); } } - template - inline void set(const ChunkSize& chunksize, Args ... args) { + template + inline void set(const ChunkSize& chunksize, Args... args) { first_arg = false; internal_policy::internal_set_chunk_size(chunksize.value); set(args...); } - template - inline void set(const ScratchRequest& scr_request, Args ... args) { + template + inline void set(const ScratchRequest& scr_request, Args... args) { first_arg = false; - internal_policy::internal_set_scratch_size(scr_request.level,Impl::PerTeamValue(scr_request.per_team), + internal_policy::internal_set_scratch_size( + scr_request.level, Impl::PerTeamValue(scr_request.per_team), Impl::PerThreadValue(scr_request.per_thread)); set(args...); } @@ -686,267 +721,287 @@ public: return TeamPolicy(internal_policy::set_chunk_size(chunk)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerTeamValue& per_team) const { - return TeamPolicy(internal_policy::set_scratch_size(level,per_team)); + inline TeamPolicy set_scratch_size(const int& level, + const Impl::PerTeamValue& per_team) const { + return TeamPolicy(internal_policy::set_scratch_size(level, per_team)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread) const { - return TeamPolicy(internal_policy::set_scratch_size(level,per_thread)); + inline TeamPolicy set_scratch_size( + const int& level, const Impl::PerThreadValue& per_thread) const { + return TeamPolicy(internal_policy::set_scratch_size(level, per_thread)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerTeamValue& per_team, const Impl::PerThreadValue& per_thread) const { - return TeamPolicy(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy set_scratch_size( + const int& level, const Impl::PerTeamValue& per_team, + const Impl::PerThreadValue& per_thread) const { + return TeamPolicy( + internal_policy::set_scratch_size(level, per_team, per_thread)); } - inline TeamPolicy set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread, const Impl::PerTeamValue& per_team) const { - return TeamPolicy(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy set_scratch_size(const int& level, + const Impl::PerThreadValue& per_thread, + const Impl::PerTeamValue& per_team) const { + return TeamPolicy( + internal_policy::set_scratch_size(level, per_team, per_thread)); } #else inline TeamPolicy& set_chunk_size(int chunk) { - static_assert(std::is_same::value, "internal set_chunk_size should return a reference"); + static_assert(std::is_same::value, + "internal set_chunk_size should return a reference"); return static_cast(internal_policy::set_chunk_size(chunk)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerTeamValue& per_team) { - static_assert(std::is_same::value, "internal set_chunk_size should return a reference"); - return static_cast(internal_policy::set_scratch_size(level,per_team)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerTeamValue& per_team) { + static_assert(std::is_same::value, + "internal set_chunk_size should return a reference"); + return static_cast( + internal_policy::set_scratch_size(level, per_team)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread) { - return static_cast(internal_policy::set_scratch_size(level,per_thread)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerThreadValue& per_thread) { + return static_cast( + internal_policy::set_scratch_size(level, per_thread)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerTeamValue& per_team, const Impl::PerThreadValue& per_thread) { - return static_cast(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerTeamValue& per_team, + const Impl::PerThreadValue& per_thread) { + return static_cast( + internal_policy::set_scratch_size(level, per_team, per_thread)); } - inline TeamPolicy& set_scratch_size(const int& level, const Impl::PerThreadValue& per_thread, const Impl::PerTeamValue& per_team) { - return static_cast(internal_policy::set_scratch_size(level, per_team, per_thread)); + inline TeamPolicy& set_scratch_size(const int& level, + const Impl::PerThreadValue& per_thread, + const Impl::PerTeamValue& per_team) { + return static_cast( + internal_policy::set_scratch_size(level, per_team, per_thread)); } #endif - }; namespace Impl { -template +template struct TeamThreadRangeBoundariesStruct { -private: - - KOKKOS_INLINE_FUNCTION static - iType ibegin( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - return arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * arg_rank ; - } - - KOKKOS_INLINE_FUNCTION static - iType iend( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - const iType end_ = arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * ( arg_rank + 1 ); - return end_ < arg_end ? end_ : arg_end ; - } + private: + KOKKOS_INLINE_FUNCTION static iType ibegin(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + return arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * arg_rank; + } -public: + KOKKOS_INLINE_FUNCTION static iType iend(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + const iType end_ = + arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * (arg_rank + 1); + return end_ < arg_end ? end_ : arg_end; + } + public: typedef iType index_type; const iType start; const iType end; - enum {increment = 1}; + enum { increment = 1 }; const TeamMemberType& thread; KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_end - ) - : start( ibegin( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamThreadRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_end) + : start( + ibegin(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + end(iend(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + thread(arg_thread) {} KOKKOS_INLINE_FUNCTION - TeamThreadRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_begin - , const iType& arg_end - ) - : start( ibegin( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamThreadRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_begin, const iType& arg_end) + : start(ibegin(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + end(iend(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + thread(arg_thread) {} }; -template +template struct TeamVectorRangeBoundariesStruct { -private: - - KOKKOS_INLINE_FUNCTION static - iType ibegin( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - return arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * arg_rank ; - } - - KOKKOS_INLINE_FUNCTION static - iType iend( const iType & arg_begin - , const iType & arg_end - , const iType & arg_rank - , const iType & arg_size - ) - { - const iType end_ = arg_begin + ( ( arg_end - arg_begin + arg_size - 1 ) / arg_size ) * ( arg_rank + 1 ); - return end_ < arg_end ? end_ : arg_end ; - } + private: + KOKKOS_INLINE_FUNCTION static iType ibegin(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + return arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * arg_rank; + } -public: + KOKKOS_INLINE_FUNCTION static iType iend(const iType& arg_begin, + const iType& arg_end, + const iType& arg_rank, + const iType& arg_size) { + const iType end_ = + arg_begin + + ((arg_end - arg_begin + arg_size - 1) / arg_size) * (arg_rank + 1); + return end_ < arg_end ? end_ : arg_end; + } + public: typedef iType index_type; const iType start; const iType end; - enum {increment = 1}; + enum { increment = 1 }; const TeamMemberType& thread; KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_end - ) - : start( ibegin( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( 0 , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamVectorRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_end) + : start( + ibegin(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + end(iend(0, arg_end, arg_thread.team_rank(), arg_thread.team_size())), + thread(arg_thread) {} KOKKOS_INLINE_FUNCTION - TeamVectorRangeBoundariesStruct( const TeamMemberType& arg_thread - , const iType& arg_begin - , const iType& arg_end - ) - : start( ibegin( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , end( iend( arg_begin , arg_end , arg_thread.team_rank() , arg_thread.team_size() ) ) - , thread( arg_thread ) - {} + TeamVectorRangeBoundariesStruct(const TeamMemberType& arg_thread, + const iType& arg_begin, const iType& arg_end) + : start(ibegin(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + end(iend(arg_begin, arg_end, arg_thread.team_rank(), + arg_thread.team_size())), + thread(arg_thread) {} }; -template +template struct ThreadVectorRangeBoundariesStruct { typedef iType index_type; const index_type start; const index_type end; - enum {increment = 1}; + enum { increment = 1 }; KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const TeamMemberType, const index_type& count ) noexcept - : start( static_cast(0) ) - , end( count ) {} + constexpr ThreadVectorRangeBoundariesStruct(const TeamMemberType, + const index_type& count) noexcept + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const index_type& count ) noexcept - : start( static_cast(0) ) - , end( count ) {} + constexpr ThreadVectorRangeBoundariesStruct(const index_type& count) noexcept + : start(static_cast(0)), end(count) {} KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const TeamMemberType, const index_type& arg_begin, const index_type& arg_end ) noexcept - : start( static_cast(arg_begin) ) - , end( arg_end ) {} + constexpr ThreadVectorRangeBoundariesStruct( + const TeamMemberType, const index_type& arg_begin, + const index_type& arg_end) noexcept + : start(static_cast(arg_begin)), end(arg_end) {} KOKKOS_INLINE_FUNCTION - constexpr ThreadVectorRangeBoundariesStruct ( const index_type& arg_begin, const index_type& arg_end ) noexcept - : start( static_cast(arg_begin) ) - , end( arg_end ) {} + constexpr ThreadVectorRangeBoundariesStruct( + const index_type& arg_begin, const index_type& arg_end) noexcept + : start(static_cast(arg_begin)), end(arg_end) {} }; -template +template struct ThreadSingleStruct { const TeamMemberType& team_member; KOKKOS_INLINE_FUNCTION - ThreadSingleStruct( const TeamMemberType& team_member_ ) : team_member( team_member_ ) {} + ThreadSingleStruct(const TeamMemberType& team_member_) + : team_member(team_member_) {} }; -template +template struct VectorSingleStruct { const TeamMemberType& team_member; KOKKOS_INLINE_FUNCTION - VectorSingleStruct( const TeamMemberType& team_member_ ) : team_member( team_member_ ) {} + VectorSingleStruct(const TeamMemberType& team_member_) + : team_member(team_member_) {} }; -} // namespace Impl +} // namespace Impl /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a single count. So the range is (0,count]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a single count. So the range is (0,count]. */ -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct -TeamThreadRange( const TeamMemberType&, const iType& count ) = delete; + Impl::TeamThreadRangeBoundariesStruct + TeamThreadRange(const TeamMemberType&, const iType& count) = delete; /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a begin and end. So the range is (begin,end]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a begin and end. So the range is (begin,end]. */ -template -KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct::type, TeamMemberType> -TeamThreadRange( const TeamMemberType&, const iType1& begin, const iType2& end ) = delete; +template +KOKKOS_INLINE_FUNCTION_DELETED Impl::TeamThreadRangeBoundariesStruct< + typename std::common_type::type, TeamMemberType> +TeamThreadRange(const TeamMemberType&, const iType1& begin, + const iType2& end) = delete; /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a single count. So the range is (0,count]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a single count. So the range is (0,count]. */ -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct -TeamVectorRange( const TeamMemberType&, const iType& count ) = delete; + Impl::TeamThreadRangeBoundariesStruct + TeamVectorRange(const TeamMemberType&, const iType& count) = delete; /** \brief Execution policy for parallel work over a threads within a team. * - * The range is split over all threads in a team. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a begin and end. So the range is (begin,end]. + * The range is split over all threads in a team. The Mapping scheme depends on + * the architecture. This policy is used together with a parallel pattern as a + * nested layer within a kernel launched with the TeamPolicy. This variant + * expects a begin and end. So the range is (begin,end]. */ -template -KOKKOS_INLINE_FUNCTION_DELETED -Impl::TeamThreadRangeBoundariesStruct::type, TeamMemberType> -TeamVectorRange( const TeamMemberType&, const iType1& begin, const iType2& end ) = delete; +template +KOKKOS_INLINE_FUNCTION_DELETED Impl::TeamThreadRangeBoundariesStruct< + typename std::common_type::type, TeamMemberType> +TeamVectorRange(const TeamMemberType&, const iType1& begin, + const iType2& end) = delete; /** \brief Execution policy for a vector parallel loop. * - * The range is split over all vector lanes in a thread. The Mapping scheme depends on the architecture. - * This policy is used together with a parallel pattern as a nested layer within a kernel launched - * with the TeamPolicy. This variant expects a single count. So the range is (0,count]. + * The range is split over all vector lanes in a thread. The Mapping scheme + * depends on the architecture. This policy is used together with a parallel + * pattern as a nested layer within a kernel launched with the TeamPolicy. This + * variant expects a single count. So the range is (0,count]. */ -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange( const TeamMemberType&, const iType& count ) = delete; + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const TeamMemberType&, const iType& count) = delete; -template +template KOKKOS_INLINE_FUNCTION_DELETED -Impl::ThreadVectorRangeBoundariesStruct -ThreadVectorRange( const TeamMemberType&, const iType& arg_begin, const iType& arg_end ) = delete; + Impl::ThreadVectorRangeBoundariesStruct + ThreadVectorRange(const TeamMemberType&, const iType& arg_begin, + const iType& arg_end) = delete; #if defined(KOKKOS_ENABLE_PROFILING) namespace Impl { -template::value > +template ::value> struct ParallelConstructName; -template +template struct ParallelConstructName { - ParallelConstructName(std::string const& label):label_ref(label) { + ParallelConstructName(std::string const& label) : label_ref(label) { if (label.empty()) { default_name = std::string(typeid(FunctorType).name()) + "/" + - typeid(TagType).name(); + typeid(TagType).name(); } } std::string const& get() { @@ -956,9 +1011,9 @@ struct ParallelConstructName { std::string default_name; }; -template +template struct ParallelConstructName { - ParallelConstructName(std::string const& label):label_ref(label) { + ParallelConstructName(std::string const& label) : label_ref(label) { if (label.empty()) { default_name = std::string(typeid(FunctorType).name()); } @@ -970,49 +1025,54 @@ struct ParallelConstructName { std::string default_name; }; -} // namespace Impl +} // namespace Impl #endif /* defined KOKKOS_ENABLE_PROFILING */ -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Experimental { namespace Impl { - template - struct PolicyPropertyAdaptor; - - template - struct PolicyPropertyAdaptor,RangePolicy> { - typedef RangePolicy policy_in_t; - typedef RangePolicy> policy_out_t; - }; - - template - struct PolicyPropertyAdaptor,TeamPolicy> { - typedef TeamPolicy policy_in_t; - typedef TeamPolicy> policy_out_t; - }; -} +template +struct PolicyPropertyAdaptor; + +template +struct PolicyPropertyAdaptor, + RangePolicy> { + typedef RangePolicy policy_in_t; + typedef RangePolicy> + policy_out_t; +}; -template -constexpr typename Impl::PolicyPropertyAdaptor,PolicyType>::policy_out_t - require(const PolicyType p, WorkItemProperty::ImplWorkItemProperty

    ){ - return typename Impl::PolicyPropertyAdaptor,PolicyType>::policy_out_t(p); +template +struct PolicyPropertyAdaptor, + TeamPolicy> { + typedef TeamPolicy policy_in_t; + typedef TeamPolicy> + policy_out_t; +}; +} // namespace Impl + +template +constexpr typename Impl::PolicyPropertyAdaptor< + WorkItemProperty::ImplWorkItemProperty

    , PolicyType>::policy_out_t +require(const PolicyType p, WorkItemProperty::ImplWorkItemProperty

    ) { + return typename Impl::PolicyPropertyAdaptor< + WorkItemProperty::ImplWorkItemProperty

    , PolicyType>::policy_out_t(p); } -} //Experimental -} //Kokkos +} // namespace Experimental +} // namespace Kokkos #endif /* #define KOKKOS_EXECPOLICY_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Extents.hpp b/lib/kokkos/core/src/Kokkos_Extents.hpp index c8b9110485..2e07e8b76b 100644 --- a/lib/kokkos/core/src/Kokkos_Extents.hpp +++ b/lib/kokkos/core/src/Kokkos_Extents.hpp @@ -2,10 +2,10 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 +// Kokkos v. 3.0 // Copyright (2019) Sandia Corporation // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -60,9 +60,7 @@ template struct PrependExtent; template -struct PrependExtent< - Extents, NewExtent -> { +struct PrependExtent, NewExtent> { using type = Extents; }; @@ -70,117 +68,101 @@ template struct AppendExtent; template -struct AppendExtent< - Extents, NewExtent -> { +struct AppendExtent, NewExtent> { using type = Extents; }; -} // end namespace Experimental +} // end namespace Experimental namespace Impl { namespace _parse_view_extents_impl { template -struct _all_remaining_extents_dynamic : std::true_type { }; +struct _all_remaining_extents_dynamic : std::true_type {}; template -struct _all_remaining_extents_dynamic - : _all_remaining_extents_dynamic -{ }; +struct _all_remaining_extents_dynamic : _all_remaining_extents_dynamic { +}; template -struct _all_remaining_extents_dynamic - : std::false_type -{ }; +struct _all_remaining_extents_dynamic : std::false_type {}; -template +template struct _parse_impl { using type = Result; }; -// We have to treat the case of int**[x] specially, since it *doesn't* go backwards +// We have to treat the case of int**[x] specially, since it *doesn't* go +// backwards template struct _parse_impl< - T*, Experimental::Extents, - typename std::enable_if<_all_remaining_extents_dynamic::value>::type -> - : _parse_impl< - T, Experimental::Extents - > -{ }; + T*, Experimental::Extents, + typename std::enable_if<_all_remaining_extents_dynamic::value>::type> + : _parse_impl> {}; // int*(*[x])[y] should still work also (meaning int[][x][][y]) template -struct _parse_impl< - T*, Experimental::Extents, - typename std::enable_if::value>::type -> -{ +struct _parse_impl, + typename std::enable_if< + not _all_remaining_extents_dynamic::value>::type> { using _next = Kokkos::Experimental::AppendExtent< - typename _parse_impl, void>::type, - Experimental::dynamic_extent - >; + typename _parse_impl, void>::type, + Experimental::dynamic_extent>; using type = typename _next::type; }; template -struct _parse_impl< - T[N], Experimental::Extents, void -> - : _parse_impl< - T, Experimental::Extents // TODO @pedantic this could be a narrowing cast - > -{ }; +struct _parse_impl, void> + : _parse_impl // TODO @pedantic this + // could be a + // narrowing cast + > {}; -} // end namespace _parse_view_extents_impl +} // end namespace _parse_view_extents_impl template struct ParseViewExtents { - using type = - typename _parse_view_extents_impl - ::_parse_impl>::type; + using type = typename _parse_view_extents_impl ::_parse_impl< + DataType, Experimental::Extents<>>::type; }; template -struct ApplyExtent -{ +struct ApplyExtent { using type = ValueType[Ext]; }; template -struct ApplyExtent -{ +struct ApplyExtent { using type = ValueType*; }; template -struct ApplyExtent -{ +struct ApplyExtent { using type = typename ApplyExtent::type[N]; }; template -struct ApplyExtent -{ - using type = ValueType*[Ext]; +struct ApplyExtent { + using type = ValueType * [Ext]; }; template -struct ApplyExtent -{ - using type = typename ApplyExtent::type*; +struct ApplyExtent { + using type = + typename ApplyExtent::type*; }; template -struct ApplyExtent -{ - using type = typename ApplyExtent::type[N]; +struct ApplyExtent { + using type = + typename ApplyExtent::type[N]; }; -} // end namespace Impl +} // end namespace Impl -} // end namespace Kokkos +} // end namespace Kokkos -#endif //KOKKOS_KOKKOS_EXTENTS_HPP +#endif // KOKKOS_KOKKOS_EXTENTS_HPP diff --git a/lib/kokkos/core/src/Kokkos_Future.hpp b/lib/kokkos/core/src/Kokkos_Future.hpp index 665ce71cf5..15a5d39aad 100644 --- a/lib/kokkos/core/src/Kokkos_Future.hpp +++ b/lib/kokkos/core/src/Kokkos_Future.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) #include #include @@ -58,7 +59,7 @@ #include #include -#include // is_space +#include // is_space //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -66,202 +67,165 @@ namespace Kokkos { // For now, hack this in as a partial specialization -// TODO @tasking @cleanup Make this the "normal" class template and make the old code the specialization +// TODO @tasking @cleanup Make this the "normal" class template and make the old +// code the specialization template -class BasicFuture> -{ -public: - - using value_type = ValueType; +class BasicFuture> { + public: + using value_type = ValueType; using execution_space = ExecutionSpace; - using scheduler_type = SimpleTaskScheduler; - using queue_type = typename scheduler_type::task_queue_type; - - -private: + using scheduler_type = SimpleTaskScheduler; + using queue_type = typename scheduler_type::task_queue_type; + private: template friend class SimpleTaskScheduler; template friend class BasicFuture; - using task_base_type = typename scheduler_type::task_base_type; + using task_base_type = typename scheduler_type::task_base_type; using task_queue_type = typename scheduler_type::task_queue_type; using task_queue_traits = typename scheduler_type::task_queue_traits; - using task_scheduling_info_type = typename scheduler_type::task_scheduling_info_type; + using task_scheduling_info_type = + typename scheduler_type::task_scheduling_info_type; - using result_storage_type = - Impl::TaskResultStorage< + using result_storage_type = Impl::TaskResultStorage< ValueType, - Impl::SchedulingInfoStorage< - Impl::RunnableTaskBase, - task_scheduling_info_type - > - >; - - + Impl::SchedulingInfoStorage, + task_scheduling_info_type>>; OwningRawPtr m_task = nullptr; KOKKOS_INLINE_FUNCTION - explicit - BasicFuture(task_base_type* task) - : m_task(task) - { + explicit BasicFuture(task_base_type* task) : m_task(task) { // Note: reference count starts at 2 to account for initial increment - // TODO @tasking @minor DSH verify reference count here and/or encapsulate starting reference count closer to here + // TODO @tasking @minor DSH verify reference count here and/or encapsulate + // starting reference count closer to here } -public: - + public: KOKKOS_INLINE_FUNCTION - BasicFuture() noexcept : m_task(nullptr) { } + BasicFuture() noexcept : m_task(nullptr) {} KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture&& rhs) noexcept - : m_task(std::move(rhs.m_task)) - { + BasicFuture(BasicFuture&& rhs) noexcept : m_task(std::move(rhs.m_task)) { rhs.m_task = nullptr; } KOKKOS_INLINE_FUNCTION BasicFuture(BasicFuture const& rhs) - // : m_task(rhs.m_task) - : m_task(nullptr) - { + // : m_task(rhs.m_task) + : m_task(nullptr) { *static_cast(&m_task) = rhs.m_task; - if(m_task) m_task->increment_reference_count(); + if (m_task) m_task->increment_reference_count(); } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) noexcept - { - if(m_task != rhs.m_task) { + BasicFuture& operator=(BasicFuture&& rhs) noexcept { + if (m_task != rhs.m_task) { clear(); - //m_task = std::move(rhs.m_task); + // m_task = std::move(rhs.m_task); *static_cast(&m_task) = rhs.m_task; // rhs.m_task reference count is unchanged, since this is a move - } - else { + } else { // They're the same, but this is a move, so 1 fewer references now rhs.clear(); } rhs.m_task = nullptr; - return *this ; + return *this; } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture const& rhs) - { - if(m_task != rhs.m_task) { + BasicFuture& operator=(BasicFuture const& rhs) { + if (m_task != rhs.m_task) { clear(); - //m_task = rhs.m_task; + // m_task = rhs.m_task; *static_cast(&m_task) = rhs.m_task; } - if(m_task != nullptr) { m_task->increment_reference_count(); } + if (m_task != nullptr) { + m_task->increment_reference_count(); + } return *this; } //---------------------------------------- template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) - : m_task(std::move(rhs.m_task)) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Moved Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Moved Futures must have the same value_type" - ); + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) + : m_task(std::move(rhs.m_task)) { + static_assert(std::is_same::value || + std::is_same::value, + "Moved Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Moved Futures must have the same value_type"); // reference counts are unchanged, since this is a move rhs.m_task = nullptr; } template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture const& rhs) // NOLINT(google-explicit-constructor) - //: m_task(rhs.m_task) - : m_task(nullptr) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Copied Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Copied Futures must have the same value_type" - ); + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture const& rhs) // NOLINT(google-explicit-constructor) + //: m_task(rhs.m_task) + : m_task(nullptr) { + static_assert(std::is_same::value || + std::is_same::value, + "Copied Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Copied Futures must have the same value_type"); *static_cast(&m_task) = rhs.m_task; - if(m_task) m_task->increment_reference_count(); + if (m_task) m_task->increment_reference_count(); } template - KOKKOS_INLINE_FUNCTION - BasicFuture& - operator=(BasicFuture const& rhs) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same value_type" - ); - - if(m_task != rhs.m_task) { + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture const& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (m_task != rhs.m_task) { clear(); - //m_task = rhs.m_task; + // m_task = rhs.m_task; *static_cast(&m_task) = rhs.m_task; - if(m_task != nullptr) { m_task->increment_reference_count(); } + if (m_task != nullptr) { + m_task->increment_reference_count(); + } } return *this; } - template - KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) - { - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same scheduler" - ); - - static_assert( - std::is_same::value || - std::is_same::value, - "Assigned Futures must have the same value_type" - ); - - if(m_task != rhs.m_task) { + template + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture&& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (m_task != rhs.m_task) { clear(); - //m_task = std::move(rhs.m_task); + // m_task = std::move(rhs.m_task); *static_cast(&m_task) = rhs.m_task; // rhs.m_task reference count is unchanged, since this is a move - } - else { + } else { // They're the same, but this is a move, so 1 fewer references now rhs.clear(); } rhs.m_task = nullptr; - return *this ; + return *this; } KOKKOS_INLINE_FUNCTION @@ -271,22 +235,19 @@ public: KOKKOS_INLINE_FUNCTION void clear() noexcept { - if(m_task) { + if (m_task) { bool should_delete = m_task->decrement_and_check_reference_count(); - if(should_delete) { + if (should_delete) { static_cast(m_task->ready_queue_base_ptr()) - ->deallocate(std::move(*m_task)); + ->deallocate(std::move(*m_task)); } } - //m_task = nullptr; + // m_task = nullptr; *static_cast(&m_task) = nullptr; } KOKKOS_INLINE_FUNCTION - bool is_null() const noexcept { - return m_task == nullptr; - } - + bool is_null() const noexcept { return m_task == nullptr; } KOKKOS_INLINE_FUNCTION bool is_ready() const noexcept { @@ -294,14 +255,11 @@ public: } KOKKOS_INLINE_FUNCTION - const typename Impl::TaskResult< ValueType >::reference_type - get() const - { + const typename Impl::TaskResult::reference_type get() const { KOKKOS_EXPECTS(is_ready()); return static_cast(m_task)->value_reference(); - //return Impl::TaskResult::get(m_task); + // return Impl::TaskResult::get(m_task); } - }; //////////////////////////////////////////////////////////////////////////////// @@ -310,57 +268,57 @@ public: template class BasicFuture { -private: - - template< typename , typename > friend class BasicTaskScheduler ; - template< typename , typename > friend class BasicFuture ; - friend class Impl::TaskBase ; - template< typename , typename , typename > friend class Impl::Task ; - + private: + template + friend class BasicTaskScheduler; + template + friend class BasicFuture; + friend class Impl::TaskBase; + template + friend class Impl::Task; //---------------------------------------- -public: - + public: //---------------------------------------- - using scheduler_type = Scheduler; - using queue_type = typename scheduler_type::queue_type; + using scheduler_type = Scheduler; + using queue_type = typename scheduler_type::queue_type; using execution_space = typename scheduler_type::execution_space; - using value_type = ValueType; + using value_type = ValueType; //---------------------------------------- -private: - + private: //---------------------------------------- - using task_base = Impl::TaskBase; + using task_base = Impl::TaskBase; - task_base * m_task ; + task_base* m_task; - KOKKOS_INLINE_FUNCTION explicit - BasicFuture( task_base * task ) : m_task(0) - { if ( task ) queue_type::assign( & m_task , task ); } + KOKKOS_INLINE_FUNCTION explicit BasicFuture(task_base* task) : m_task(0) { + if (task) queue_type::assign(&m_task, task); + } //---------------------------------------- -public: - + public: //---------------------------------------- KOKKOS_INLINE_FUNCTION - bool is_null() const { return 0 == m_task ; } + bool is_null() const { return 0 == m_task; } KOKKOS_INLINE_FUNCTION - int reference_count() const - { return 0 != m_task ? m_task->reference_count() : 0 ; } + int reference_count() const { + return 0 != m_task ? m_task->reference_count() : 0; + } //---------------------------------------- KOKKOS_INLINE_FUNCTION - void clear() - { if ( m_task ) queue_type::assign( & m_task , (task_base*)0 ); } + void clear() { + if (m_task) queue_type::assign(&m_task, (task_base*)0); + } //---------------------------------------- @@ -370,141 +328,121 @@ public: //---------------------------------------- KOKKOS_INLINE_FUNCTION - BasicFuture() noexcept : m_task(nullptr) { } + BasicFuture() noexcept : m_task(nullptr) {} KOKKOS_INLINE_FUNCTION - BasicFuture( BasicFuture && rhs ) noexcept - : m_task( rhs.m_task ) - { + BasicFuture(BasicFuture&& rhs) noexcept : m_task(rhs.m_task) { rhs.m_task = 0; } KOKKOS_INLINE_FUNCTION - BasicFuture( const BasicFuture & rhs ) - : m_task(0) - { if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); } + BasicFuture(const BasicFuture& rhs) : m_task(0) { + if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task); + } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) noexcept - { + BasicFuture& operator=(BasicFuture&& rhs) noexcept { clear(); - m_task = rhs.m_task ; - rhs.m_task = 0 ; - return *this ; + m_task = rhs.m_task; + rhs.m_task = 0; + return *this; } KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture const& rhs) - { - if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); - return *this ; + BasicFuture& operator=(BasicFuture const& rhs) { + if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task); + return *this; } //---------------------------------------- template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) - : m_task( rhs.m_task ) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); - - rhs.m_task = 0 ; + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture&& rhs) noexcept // NOLINT(google-explicit-constructor) + : m_task(rhs.m_task) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + rhs.m_task = 0; } template - KOKKOS_INLINE_FUNCTION - BasicFuture(BasicFuture const& rhs) // NOLINT(google-explicit-constructor) - : m_task(nullptr) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); - - if ( rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); + KOKKOS_INLINE_FUNCTION BasicFuture( + BasicFuture const& rhs) // NOLINT(google-explicit-constructor) + : m_task(nullptr) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (rhs.m_task) queue_type::assign(&m_task, rhs.m_task); } template - KOKKOS_INLINE_FUNCTION - BasicFuture& - operator=(BasicFuture const& rhs) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); - - if ( m_task || rhs.m_task ) queue_type::assign( & m_task , rhs.m_task ); - return *this ; + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture const& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); + + if (m_task || rhs.m_task) queue_type::assign(&m_task, rhs.m_task); + return *this; } - template - KOKKOS_INLINE_FUNCTION - BasicFuture& operator=(BasicFuture&& rhs) - { - static_assert - ( std::is_same::value || - std::is_same::value - , "Assigned Futures must have the same scheduler" ); - - static_assert - ( std::is_same< value_type , void >::value || - std::is_same::value - , "Assigned Futures must have the same value_type" ); + template + KOKKOS_INLINE_FUNCTION BasicFuture& operator=(BasicFuture&& rhs) { + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same scheduler"); + + static_assert(std::is_same::value || + std::is_same::value, + "Assigned Futures must have the same value_type"); clear(); - m_task = rhs.m_task ; - rhs.m_task = 0 ; - return *this ; + m_task = rhs.m_task; + rhs.m_task = 0; + return *this; } //---------------------------------------- KOKKOS_INLINE_FUNCTION - int is_ready() const noexcept - { return ( 0 == m_task ) || ( ((task_base*) task_base::LockTag) == m_task->m_wait ); } + int is_ready() const noexcept { + return (0 == m_task) || + (((task_base*)task_base::LockTag) == m_task->m_wait); + } KOKKOS_INLINE_FUNCTION - const typename Impl::TaskResult< ValueType >::reference_type - get() const - { - if ( 0 == m_task ) { - Kokkos::abort( "Kokkos:::Future::get ERROR: is_null()"); + const typename Impl::TaskResult::reference_type get() const { + if (0 == m_task) { + Kokkos::abort("Kokkos:::Future::get ERROR: is_null()"); } - return Impl::TaskResult< ValueType >::get( m_task ); + return Impl::TaskResult::get(m_task); } }; // Is a Future with the given execution space -template< typename , typename ExecSpace = void > +template struct is_future : public std::false_type {}; -template +template struct is_future, ExecSpace> - : std::integral_constant::value - || std::is_void::value - > -{}; + : std::integral_constant< + bool, + std::is_same::value || + std::is_void::value> {}; //////////////////////////////////////////////////////////////////////////////// // END OLD CODE @@ -514,39 +452,32 @@ namespace Impl { template class ResolveFutureArgOrder { -private: + private: enum { Arg1_is_space = Kokkos::is_space::value }; enum { Arg2_is_space = Kokkos::is_space::value }; enum { Arg1_is_value = !Arg1_is_space && !std::is_same::value }; enum { Arg2_is_value = !Arg2_is_space && !std::is_same::value }; - static_assert( - ! ( Arg1_is_space && Arg2_is_space ), - "Future cannot be given two spaces" - ); - - static_assert( - ! ( Arg1_is_value && Arg2_is_value ), - "Future cannot be given two value types" - ); + static_assert(!(Arg1_is_space && Arg2_is_space), + "Future cannot be given two spaces"); - using value_type = - typename std::conditional::type - >::type; + static_assert(!(Arg1_is_value && Arg2_is_value), + "Future cannot be given two value types"); - using execution_space = - typename std::conditional::type - >::type::execution_space; + using value_type = typename std::conditional< + Arg1_is_value, Arg1, + typename std::conditional::type>::type; -public: + using execution_space = typename std::conditional< + Arg1_is_space, Arg1, + typename std::conditional::type>::type::execution_space; + public: using type = BasicFuture>; - }; -} // end namespace Impl +} // end namespace Impl /** * @@ -558,7 +489,7 @@ public: template using Future = typename Impl::ResolveFutureArgOrder::type; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- diff --git a/lib/kokkos/core/src/Kokkos_HBWSpace.hpp b/lib/kokkos/core/src/Kokkos_HBWSpace.hpp index aaac7cd7f9..357dcc9014 100644 --- a/lib/kokkos/core/src/Kokkos_HBWSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_HBWSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,26 +64,26 @@ namespace Impl { /// This function initializes the locks to zero (unset). void init_lock_array_hbw_space(); -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. -bool lock_address_hbw_space( void* ptr ); +bool lock_address_hbw_space(void* ptr); /// \brief Release lock for the address /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -void unlock_address_hbw_space( void* ptr ); +void unlock_address_hbw_space(void* ptr); -} // namespace Impl +} // namespace Impl -} // namespace Experimental +} // namespace Experimental -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { @@ -94,10 +95,10 @@ namespace Experimental { /// HBWSpace is a memory space that governs host memory. "Host" /// memory means the usual CPU-accessible memory. class HBWSpace { -public: + public: //! Tag this class as a kokkos memory space - typedef HBWSpace memory_space; - typedef size_t size_type; + typedef HBWSpace memory_space; + typedef size_t size_type; /// \typedef execution_space /// \brief Default execution space for this memory space. @@ -105,59 +106,64 @@ public: /// Every memory space has a default execution space. This is /// useful for things like initializing a View (which happens in /// parallel using the View's default execution space). -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Kokkos::Threads execution_space; +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) + typedef Kokkos::Threads execution_space; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_THREADS ) - typedef Kokkos::Threads execution_space; +#elif defined(KOKKOS_ENABLE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_THREADS) + typedef Kokkos::Threads execution_space; //#elif defined( KOKKOS_ENABLE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_SERIAL ) - typedef Kokkos::Serial execution_space; +#elif defined(KOKKOS_ENABLE_SERIAL) + typedef Kokkos::Serial execution_space; #else -# error "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qhreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." +#error \ + "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qhreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." #endif //! This memory space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; /**\brief Default memory space instance */ HBWSpace(); - HBWSpace( const HBWSpace & rhs ) = default; - HBWSpace & operator = ( const HBWSpace & ) = default; - ~HBWSpace() = default; + HBWSpace(const HBWSpace& rhs) = default; + HBWSpace& operator=(const HBWSpace&) = default; + ~HBWSpace() = default; - /**\brief Non-default memory space instance to choose allocation mechansim, if available */ + /**\brief Non-default memory space instance to choose allocation mechansim, + * if available */ - enum AllocationMechanism { STD_MALLOC, POSIX_MEMALIGN, POSIX_MMAP, INTEL_MM_ALLOC }; + enum AllocationMechanism { + STD_MALLOC, + POSIX_MEMALIGN, + POSIX_MMAP, + INTEL_MM_ALLOC + }; - explicit - HBWSpace( const AllocationMechanism & ); + explicit HBWSpace(const AllocationMechanism&); /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return "HBW"; } -private: - - AllocationMechanism m_alloc_mech; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::Experimental::HBWSpace, void >; + private: + AllocationMechanism m_alloc_mech; + friend class Kokkos::Impl::SharedAllocationRecord< + Kokkos::Experimental::HBWSpace, void>; }; -} // namespace Experimental +} // namespace Experimental -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -165,20 +171,18 @@ namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::Experimental::HBWSpace, void > - : public SharedAllocationRecord< void, void > -{ -private: - +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: friend Kokkos::Experimental::HBWSpace; - typedef SharedAllocationRecord< void, void > RecordBase; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG /**\brief Root record for tracked allocations from this HBWSpace instance */ @@ -187,61 +191,52 @@ private: const Kokkos::Experimental::HBWSpace m_space; -protected: - + protected: ~SharedAllocationRecord(); SharedAllocationRecord() = default; - SharedAllocationRecord( const Kokkos::Experimental::HBWSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); - -public: - - inline - std::string get_label() const - { - return std::string( RecordBase::head()->m_label ); - } - - KOKKOS_INLINE_FUNCTION static - SharedAllocationRecord * allocate( const Kokkos::Experimental::HBWSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) - { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - return new SharedAllocationRecord( arg_space, arg_label, arg_alloc_size ); + SharedAllocationRecord( + const Kokkos::Experimental::HBWSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); + + public: + inline std::string get_label() const { + return std::string(RecordBase::head()->m_label); + } + + KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate( + const Kokkos::Experimental::HBWSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size) { +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); #else - return (SharedAllocationRecord *) 0; + return (SharedAllocationRecord*)0; #endif - } + } /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::HBWSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::Experimental::HBWSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream &, const Kokkos::Experimental::HBWSpace &, bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::HBWSpace&, + bool detail = false); }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -249,25 +244,28 @@ namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::Experimental::HBWSpace, Kokkos::Experimental::HBWSpace >::assignable, "" ); +static_assert( + Kokkos::Impl::MemorySpaceAccess::assignable, + ""); -template<> -struct MemorySpaceAccess< Kokkos::HostSpace, Kokkos::Experimental::HBWSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::Experimental::HBWSpace, Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -275,70 +273,64 @@ namespace Kokkos { namespace Impl { -template< class ExecutionSpace > -struct DeepCopy< Experimental::HBWSpace, Experimental::HBWSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - memcpy( dst, src, n ); - } +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { memcpy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - memcpy( dst, src, n ); + memcpy(dst, src, n); } }; -template< class ExecutionSpace > -struct DeepCopy< HostSpace, Experimental::HBWSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - memcpy( dst, src, n ); - } +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { memcpy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - memcpy( dst, src, n ); + memcpy(dst, src, n); } }; -template< class ExecutionSpace > -struct DeepCopy< Experimental::HBWSpace, HostSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - memcpy( dst, src, n ); - } +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { memcpy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - memcpy( dst, src, n ); + memcpy(dst, src, n); } }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { namespace Impl { -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace, Kokkos::Experimental::HBWSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::Experimental::HBWSpace, Kokkos::HostSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos #endif -#endif // #define KOKKOS_HBWSPACE_HPP - +#endif // #define KOKKOS_HBWSPACE_HPP diff --git a/lib/kokkos/core/src/Kokkos_HPX.hpp b/lib/kokkos/core/src/Kokkos_HPX.hpp index 79a2b74da4..46101c824f 100644 --- a/lib/kokkos/core/src/Kokkos_HPX.hpp +++ b/lib/kokkos/core/src/Kokkos_HPX.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -57,6 +58,7 @@ #include #endif +#include #include #include #include @@ -74,7 +76,7 @@ #include #include #include -#include +#include #include #include #include @@ -97,6 +99,7 @@ // - 1: The manual way. This way is more verbose and does not take advantage of // e.g. parallel::for_loop in HPX but it is significantly faster in many // benchmarks. +// - 2: Like 1, but spawn tasks using for_loop and a custom executor. // // In the long run 0 should be the preferred implementation, but until HPX is // improved 1 will be the default. @@ -104,7 +107,7 @@ #define KOKKOS_HPX_IMPLEMENTATION 1 #endif -#if (KOKKOS_HPX_IMPLEMENTATION < 0) || (KOKKOS_HPX_IMPLEMENTATION > 1) +#if (KOKKOS_HPX_IMPLEMENTATION < 0) || (KOKKOS_HPX_IMPLEMENTATION > 2) #error "You have chosen an invalid value for KOKKOS_HPX_IMPLEMENTATION" #endif @@ -123,9 +126,11 @@ class thread_buffer { m_cache_line_size; } -public: + public: thread_buffer() - : m_num_threads(0), m_size_per_thread(0), m_size_total(0), + : m_num_threads(0), + m_size_per_thread(0), + m_size_total(0), m_data(nullptr) {} thread_buffer(const std::size_t num_threads, const std::size_t size_per_thread) { @@ -134,13 +139,13 @@ public: ~thread_buffer() { delete[] m_data; } thread_buffer(const thread_buffer &) = delete; - thread_buffer(thread_buffer &&) = delete; + thread_buffer(thread_buffer &&) = delete; thread_buffer &operator=(const thread_buffer &) = delete; thread_buffer &operator=(thread_buffer) = delete; void resize(const std::size_t num_threads, const std::size_t size_per_thread) { - m_num_threads = num_threads; + m_num_threads = num_threads; m_size_per_thread = size_per_thread; pad_to_cache_line(m_size_per_thread); @@ -149,7 +154,7 @@ public: if (m_size_total < size_total_new) { delete[] m_data; - m_data = new char[size_total_new]; + m_data = new char[size_total_new]; m_size_total = size_total_new; } } @@ -165,23 +170,23 @@ public: std::size_t size_per_thread() const noexcept { return m_size_per_thread; } std::size_t size_total() const noexcept { return m_size_total; } }; -} // namespace Impl +} // namespace Impl namespace Experimental { class HPX { -private: + private: static bool m_hpx_initialized; static Kokkos::Impl::thread_buffer m_buffer; #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) static hpx::future m_future; #endif -public: - using execution_space = HPX; - using memory_space = HostSpace; - using device_type = Kokkos::Device; - using array_layout = LayoutRight; - using size_type = memory_space::size_type; + public: + using execution_space = HPX; + using memory_space = HostSpace; + using device_type = Kokkos::Device; + using array_layout = LayoutRight; + using size_type = memory_space::size_type; using scratch_memory_space = ScratchMemorySpace; HPX() noexcept {} @@ -192,26 +197,20 @@ public: static bool in_parallel(HPX const & = HPX()) noexcept { return false; } static void impl_static_fence(HPX const & = HPX()) - #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) - { - if (hpx::threads::get_self_ptr() == nullptr) { - hpx::threads::run_as_hpx_thread([]() { impl_get_future().wait(); }); - } else { - impl_get_future().wait(); - } - } - #else - noexcept { +#if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) + { + if (hpx::threads::get_self_ptr() == nullptr) { + hpx::threads::run_as_hpx_thread([]() { impl_get_future().wait(); }); + } else { + impl_get_future().wait(); } - #endif - - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - static void fence(HPX const & = HPX()) { - #else - void fence() const { - #endif - impl_static_fence(); } +#else + noexcept { + } +#endif + + void fence() const { impl_static_fence(); } static bool is_asynchronous(HPX const & = HPX()) noexcept { #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) @@ -222,8 +221,9 @@ public: } static std::vector partition(...) { - Kokkos::abort("Kokkos::Experimental::HPX::partition_master: can't partition an HPX " - "instance\n"); + Kokkos::abort( + "Kokkos::Experimental::HPX::partition_master: can't partition an HPX " + "instance\n"); return std::vector(); } @@ -231,8 +231,9 @@ public: static void partition_master(F const &f, int requested_num_partitions = 0, int requested_partition_size = 0) { if (requested_num_partitions > 1) { - Kokkos::abort("Kokkos::Experimental::HPX::partition_master: can't partition an " - "HPX instance\n"); + Kokkos::abort( + "Kokkos::Experimental::HPX::partition_master: can't partition an " + "HPX instance\n"); } } @@ -287,13 +288,14 @@ public: static Kokkos::Impl::thread_buffer &impl_get_buffer() noexcept { return m_buffer; } + #if defined(KOKKOS_ENABLE_HPX_ASYNC_DISPATCH) static hpx::future &impl_get_future() noexcept { return m_future; } #endif static constexpr const char *name() noexcept { return "HPX"; } }; -} // namespace Experimental +} // namespace Experimental namespace Impl { template @@ -302,15 +304,15 @@ inline void dispatch_execute_task(Closure *closure) { if (hpx::threads::get_self_ptr() == nullptr) { hpx::threads::run_as_hpx_thread([closure]() { hpx::future &fut = Kokkos::Experimental::HPX::impl_get_future(); - Closure closure_copy = *closure; - fut = fut.then([closure_copy](hpx::future &&) { + Closure closure_copy = *closure; + fut = fut.then([closure_copy](hpx::future &&) { closure_copy.execute_task(); }); }); } else { hpx::future &fut = Kokkos::Experimental::HPX::impl_get_future(); - Closure closure_copy = *closure; - fut = fut.then( + Closure closure_copy = *closure; + fut = fut.then( [closure_copy](hpx::future &&) { closure_copy.execute_task(); }); } #else @@ -321,8 +323,8 @@ inline void dispatch_execute_task(Closure *closure) { } #endif } -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { @@ -342,15 +344,16 @@ struct VerifyExecutionCanAccessMemorySpace< inline static void verify(void) {} inline static void verify(const void *) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Experimental { -template <> class UniqueToken { -public: +template <> +class UniqueToken { + public: using execution_space = HPX; - using size_type = int; + using size_type = int; UniqueToken(execution_space const & = execution_space()) noexcept {} // NOTE: Currently this assumes that there is no oversubscription. @@ -361,10 +364,11 @@ public: void release(int) const noexcept {} }; -template <> class UniqueToken { -public: +template <> +class UniqueToken { + public: using execution_space = HPX; - using size_type = int; + using size_type = int; UniqueToken(execution_space const & = execution_space()) noexcept {} // NOTE: Currently this assumes that there is no oversubscription. @@ -374,28 +378,27 @@ public: int acquire() const noexcept { return HPX::impl_hardware_thread_id(); } void release(int) const noexcept {} }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos namespace Kokkos { namespace Impl { struct HPXTeamMember { -public: + public: using execution_space = Kokkos::Experimental::HPX; using scratch_memory_space = Kokkos::ScratchMemorySpace; -private: + private: scratch_memory_space m_team_shared; - std::size_t m_team_shared_size; int m_league_size; int m_league_rank; int m_team_size; int m_team_rank; -public: + public: KOKKOS_INLINE_FUNCTION const scratch_memory_space &team_shmem() const { return m_team_shared.set_team_thread_mode(0, 1, 0); @@ -423,14 +426,15 @@ public: KOKKOS_INLINE_FUNCTION int team_size() const noexcept { return m_team_size; } template - constexpr KOKKOS_INLINE_FUNCTION - HPXTeamMember(const TeamPolicyInternal &policy, - const int team_rank, const int league_rank, void *scratch, - int scratch_size) noexcept + constexpr KOKKOS_INLINE_FUNCTION HPXTeamMember( + const TeamPolicyInternal + &policy, + const int team_rank, const int league_rank, void *scratch, + int scratch_size) noexcept : m_team_shared(scratch, scratch_size, scratch, scratch_size), - m_team_shared_size(scratch_size), m_league_size(policy.league_size()), - m_league_rank(league_rank), m_team_size(policy.team_size()), + m_league_size(policy.league_size()), + m_league_rank(league_rank), + m_team_size(policy.team_size()), m_team_rank(team_rank) {} KOKKOS_INLINE_FUNCTION @@ -482,7 +486,7 @@ class TeamPolicyInternal std::size_t m_thread_scratch_size[2]; int m_chunk_size; -public: + public: using member_type = HPXTeamMember; // NOTE: Max size is 1 for simplicity. In most cases more than 1 is not @@ -511,21 +515,35 @@ public: int team_size_max(const FunctorType &, const ParallelReduceTag &) const { return 1; } + + template + int team_size_max(const FunctorType &, const ReducerType &, + const ParallelReduceTag &) const { + return 1; + } + template int team_size_recommended(const FunctorType &, const ParallelForTag &) const { return 1; } + template int team_size_recommended(const FunctorType &, const ParallelReduceTag &) const { return 1; } -private: + template + int team_size_recommended(const FunctorType &, const ReducerType &, + const ParallelReduceTag &) const { + return 1; + } + + private: inline void init(const int league_size_request, const int team_size_request) { - m_league_size = league_size_request; - const int max_team_size = 1; // TODO: Can't use team_size_max(...) because - // it requires a functor as argument. + m_league_size = league_size_request; + const int max_team_size = 1; // TODO: Can't use team_size_max(...) because + // it requires a functor as argument. m_team_size = team_size_request > max_team_size ? max_team_size : team_size_request; @@ -551,7 +569,7 @@ private: } } -public: + public: inline int team_size() const { return m_team_size; } inline int league_size() const { return m_league_size; } @@ -563,26 +581,32 @@ public: team_size_ * m_thread_scratch_size[level]; } -public: + inline static int scratch_size_max(int level) { + return (level == 0 ? 1024 * 32 : // Roughly L1 size + 20 * 1024 * 1024); // Limit to keep compatibility with CUDA + } + + public: template friend class TeamPolicyInternal; template - TeamPolicyInternal( - const TeamPolicyInternal &p) { - m_league_size = p.m_league_size; - m_team_size = p.m_team_size; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; + TeamPolicyInternal(const TeamPolicyInternal &p) { + m_league_size = p.m_league_size; + m_team_size = p.m_team_size; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; + m_chunk_size = p.m_chunk_size; } TeamPolicyInternal(const typename traits::execution_space &, int league_size_request, int team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, team_size_request); } @@ -591,14 +615,16 @@ public: int league_size_request, const Kokkos::AUTO_t &team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, 1); } TeamPolicyInternal(int league_size_request, int team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, team_size_request); } @@ -606,15 +632,16 @@ public: TeamPolicyInternal(int league_size_request, const Kokkos::AUTO_t &team_size_request, int /* vector_length_request */ = 1) - : m_team_scratch_size{0, 0}, m_thread_scratch_size{0, 0}, + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, m_chunk_size(0) { init(league_size_request, 1); } inline int chunk_size() const { return m_chunk_size; } - inline TeamPolicyInternal & - set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal &set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } @@ -625,22 +652,22 @@ public: return *this; } - inline TeamPolicyInternal & - set_scratch_size(const int &level, const PerThreadValue &per_thread) { + inline TeamPolicyInternal &set_scratch_size( + const int &level, const PerThreadValue &per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - inline TeamPolicyInternal & - set_scratch_size(const int &level, const PerTeamValue &per_team, - const PerThreadValue &per_thread) { - m_team_scratch_size[level] = per_team.value; + inline TeamPolicyInternal &set_scratch_size( + const int &level, const PerTeamValue &per_team, + const PerThreadValue &per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { @@ -648,11 +675,11 @@ namespace Impl { template class ParallelFor, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; const FunctorType m_functor; const Policy m_policy; @@ -689,7 +716,7 @@ private: } } -public: + public: void execute() const { Kokkos::Impl::dispatch_execute_task(this); } void execute_task() const { @@ -705,25 +732,44 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, i_begin]() { const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); execute_functor_range(m_functor, i_begin, i_end); - sem.signal(1); + num_tasks_remaining.count_down(1); }); - - ++num_tasks; } - sem.wait(num_tasks); + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), [this](const Member i_begin) { + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + execute_functor_range(m_functor, i_begin, i_end); + }); #endif } @@ -734,12 +780,12 @@ public: template class ParallelFor, Kokkos::Experimental::HPX> { -private: + private: using MDRangePolicy = Kokkos::MDRangePolicy; - using Policy = typename MDRangePolicy::impl_range_policy; - using WorkTag = typename MDRangePolicy::work_tag; - using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Policy = typename MDRangePolicy::impl_range_policy; + using WorkTag = typename MDRangePolicy::work_tag; + using WorkRange = typename Policy::WorkRange; + using Member = typename Policy::member_type; using iterate_type = typename Kokkos::Impl::HostIterateTile; @@ -748,7 +794,7 @@ private: const MDRangePolicy m_mdr_policy; const Policy m_policy; -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { @@ -764,47 +810,69 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, i_begin]() { const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); for (Member i = i_begin; i < i_end; ++i) { iterate_type(m_mdr_policy, m_functor)(i); } - sem.signal(1); + num_tasks_remaining.count_down(1); }); - - ++num_tasks; } - sem.wait(num_tasks); + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), [this](const Member i_begin) { + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + for (Member i = i_begin; i < i_end; ++i) { + iterate_type(m_mdr_policy, m_functor)(i); + } + }); #endif } inline ParallelFor(const FunctorType &arg_functor, MDRangePolicy arg_policy) - : m_functor(arg_functor), m_mdr_policy(arg_policy), + : m_functor(arg_functor), + m_mdr_policy(arg_policy), m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { template class ParallelReduce, ReducerType, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using Analysis = FunctorAnalysis; using ReducerConditional = @@ -814,11 +882,11 @@ private: using WorkTagFwd = typename Kokkos::Impl::if_c::value, WorkTag, void>::type; - using ValueInit = Kokkos::Impl::FunctorValueInit; - using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; + using ValueInit = Kokkos::Impl::FunctorValueInit; + using ValueJoin = Kokkos::Impl::FunctorValueJoin; + using ValueOps = Kokkos::Impl::FunctorValueOps; using value_type = typename Analysis::value_type; - using pointer_type = typename Analysis::pointer_type; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; const FunctorType m_functor; @@ -866,11 +934,11 @@ private: } class value_type_wrapper { - private: + private: std::size_t m_value_size; char *m_value_buffer; - public: + public: value_type_wrapper() : m_value_size(0), m_value_buffer(nullptr) {} value_type_wrapper(const std::size_t value_size) @@ -880,7 +948,7 @@ private: : m_value_size(0), m_value_buffer(nullptr) { if (this != &other) { m_value_buffer = new char[other.m_value_size]; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; std::copy(other.m_value_buffer, other.m_value_buffer + m_value_size, m_value_buffer); @@ -893,10 +961,10 @@ private: : m_value_size(0), m_value_buffer(nullptr) { if (this != &other) { m_value_buffer = other.m_value_buffer; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; other.m_value_buffer = nullptr; - other.m_value_size = 0; + other.m_value_size = 0; } } @@ -904,7 +972,7 @@ private: if (this != &other) { delete[] m_value_buffer; m_value_buffer = new char[other.m_value_size]; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; std::copy(other.m_value_buffer, other.m_value_buffer + m_value_size, m_value_buffer); @@ -917,10 +985,10 @@ private: if (this != &other) { delete[] m_value_buffer; m_value_buffer = other.m_value_buffer; - m_value_size = other.m_value_size; + m_value_size = other.m_value_size; other.m_value_buffer = nullptr; - other.m_value_size = 0; + other.m_value_size = 0; } return *this; @@ -936,26 +1004,21 @@ private: } }; -public: - void execute() const { - dispatch_execute_task(this); - } + public: + void execute() const { dispatch_execute_task(this); } inline void execute_task() const { - const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); - - std::size_t value_size = + const std::size_t value_size = Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); - using hpx::parallel::for_loop; - using hpx::parallel::execution::par; - #if KOKKOS_HPX_IMPLEMENTATION == 0 // NOTE: This version makes the most use of HPX functionality, but // requires the struct value_type_wrapper to handle different // reference_types. It is also significantly slower than the version // below due to not reusing the buffer used by other functions. + using hpx::parallel::for_loop; using hpx::parallel::reduction; + using hpx::parallel::execution::par; using hpx::parallel::execution::static_chunk_size; value_type_wrapper final_value(value_size); @@ -983,37 +1046,99 @@ public: pointer_type final_value_ptr = final_value.pointer(); #elif KOKKOS_HPX_IMPLEMENTATION == 1 + const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); + thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, value_size); - for_loop(par, 0, num_worker_threads, [this, &buffer](std::size_t t) { - ValueInit::init(ReducerConditional::select(m_functor, m_reducer), - reinterpret_cast(buffer.get(t))); - }); - using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; + + { + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &num_tasks_remaining, &buffer, t]() { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + + num_tasks_remaining.count_down(1); + }); + } + + num_tasks_remaining.wait(); + } - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, &buffer, i_begin]() { reference_type update = - ValueOps::reference(reinterpret_cast( - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); execute_functor_range(update, i_begin, i_end); - sem.signal(1); + num_tasks_remaining.count_down(1); }); + } + + num_tasks_remaining.wait(); - ++num_tasks; + for (int i = 1; i < num_worker_threads; ++i) { + ValueJoin::join(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(0)), + reinterpret_cast(buffer.get(i))); } - sem.wait(num_tasks); + pointer_type final_value_ptr = + reinterpret_cast(buffer.get(0)); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); + + thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); + buffer.resize(num_worker_threads, value_size); + + using hpx::parallel::for_loop; + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + { + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for_loop(par.on(exec).with(static_chunk_size(1)), std::size_t(0), + num_worker_threads, [this, &buffer](const std::size_t t) { + ValueInit::init( + ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + }); + } + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), + [this, &buffer](const Member i_begin) { + reference_type update = + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + execute_functor_range(update, i_begin, i_end); + }); for (int i = 1; i < num_worker_threads; ++i) { ValueJoin::join(ReducerConditional::select(m_functor, m_reducer), @@ -1045,13 +1170,17 @@ public: typename std::enable_if::value && !Kokkos::is_reducer_type::value, void *>::type = NULL) - : m_functor(arg_functor), m_policy(arg_policy), m_reducer(InvalidType()), + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), m_result_ptr(arg_view.data()), m_force_synchronous(!arg_view.impl_track().has_record()) {} inline ParallelReduce(const FunctorType &arg_functor, Policy arg_policy, const ReducerType &reducer) - : m_functor(arg_functor), m_policy(arg_policy), m_reducer(reducer), + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), m_result_ptr(reducer.view().data()), m_force_synchronous(!reducer.view().impl_track().has_record()) {} }; @@ -1059,13 +1188,13 @@ public: template class ParallelReduce, ReducerType, Kokkos::Experimental::HPX> { -private: + private: using MDRangePolicy = Kokkos::MDRangePolicy; - using Policy = typename MDRangePolicy::impl_range_policy; - using WorkTag = typename MDRangePolicy::work_tag; - using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; - using Analysis = FunctorAnalysis; using ReducerConditional = Kokkos::Impl::if_c::value, @@ -1076,9 +1205,9 @@ private: WorkTag, void>::type; using ValueInit = Kokkos::Impl::FunctorValueInit; using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; - using value_type = typename Analysis::value_type; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; + using value_type = typename Analysis::value_type; using reference_type = typename Analysis::reference_type; using iterate_type = typename Kokkos::Impl::HostIterateTile(buffer.get(t))); }); -#if KOKKOS_HPX_IMPLEMENTATION == 0 - using hpx::parallel::execution::static_chunk_size; - for_loop(par.with(static_chunk_size(m_policy.chunk_size())), m_policy.begin(), m_policy.end(), [this, &buffer](const Member i) { reference_type update = ValueOps::reference( @@ -1126,17 +1252,36 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; + + { + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &buffer, &num_tasks_remaining, t]() { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + + num_tasks_remaining.count_down(1); + }); + } - counting_semaphore sem(0); - std::size_t num_tasks = 0; + num_tasks_remaining.wait(); + } + + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (Member i_begin = m_policy.begin(); i_begin < m_policy.end(); i_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, i_begin]() { + apply(exec, [this, &num_tasks_remaining, &buffer, i_begin]() { reference_type update = - ValueOps::reference(reinterpret_cast( - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); const Member i_end = (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); @@ -1144,13 +1289,48 @@ public: iterate_type(m_mdr_policy, m_functor, update)(i); } - sem.signal(1); + num_tasks_remaining.count_down(1); }); + } + + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop; + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; - ++num_tasks; + { + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for_loop(par.on(exec).with(static_chunk_size(1)), std::size_t(0), + num_worker_threads, [this, &buffer](const std::size_t t) { + ValueInit::init( + ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + }); } - sem.wait(num_tasks); + const int num_tasks = + (m_policy.end() - m_policy.begin() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), m_policy.begin(), + m_policy.end(), m_policy.chunk_size(), + [this, &buffer](const Member i_begin) { + reference_type update = + ValueOps::reference(reinterpret_cast(buffer.get( + Kokkos::Experimental::HPX::impl_hardware_thread_id()))); + const Member i_end = + (std::min)(i_begin + m_policy.chunk_size(), m_policy.end()); + + for (Member i = i_begin; i < i_end; ++i) { + iterate_type(m_mdr_policy, m_functor, update)(i); + } + }); #endif for (int i = 1; i < num_worker_threads; ++i) { @@ -1180,20 +1360,24 @@ public: typename std::enable_if::value && !Kokkos::is_reducer_type::value, void *>::type = NULL) - : m_functor(arg_functor), m_mdr_policy(arg_policy), + : m_functor(arg_functor), + m_mdr_policy(arg_policy), m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), - m_reducer(InvalidType()), m_result_ptr(arg_view.data()), + m_reducer(InvalidType()), + m_result_ptr(arg_view.data()), m_force_synchronous(!arg_view.impl_track().has_record()) {} inline ParallelReduce(const FunctorType &arg_functor, MDRangePolicy arg_policy, const ReducerType &reducer) - : m_functor(arg_functor), m_mdr_policy(arg_policy), + : m_functor(arg_functor), + m_mdr_policy(arg_policy), m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), - m_reducer(reducer), m_result_ptr(reducer.view().data()), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), m_force_synchronous(!reducer.view().impl_track().has_record()) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { @@ -1201,19 +1385,19 @@ namespace Impl { template class ParallelScan, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using Analysis = FunctorAnalysis; - using ValueInit = Kokkos::Impl::FunctorValueInit; - using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; + using ValueInit = Kokkos::Impl::FunctorValueInit; + using ValueJoin = Kokkos::Impl::FunctorValueJoin; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; - using value_type = typename Analysis::value_type; + using value_type = typename Analysis::value_type; const FunctorType m_functor; const Policy m_policy; @@ -1241,64 +1425,70 @@ private: } } -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); - const int value_count = Analysis::value_count(m_functor); + const int value_count = Analysis::value_count(m_functor); const std::size_t value_size = Analysis::value_size(m_functor); thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, 2 * value_size); + using hpx::apply; using hpx::lcos::local::barrier; - using hpx::parallel::for_loop; - using hpx::parallel::execution::par; - using hpx::parallel::execution::static_chunk_size; + using hpx::lcos::local::latch; barrier bar(num_worker_threads); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &bar, &buffer, &num_tasks_remaining, + num_worker_threads, value_count, value_size, t]() { + reference_type update_sum = ValueInit::init( + m_functor, reinterpret_cast(buffer.get(t))); + + const WorkRange range(m_policy, t, num_worker_threads); + execute_functor_range(m_functor, range.begin(), range.end(), + update_sum, false); + + bar.wait(); + + if (t == 0) { + ValueInit::init(m_functor, reinterpret_cast( + buffer.get(0) + value_size)); + + for (int i = 1; i < num_worker_threads; ++i) { + pointer_type ptr_1_prev = + reinterpret_cast(buffer.get(i - 1)); + pointer_type ptr_2_prev = + reinterpret_cast(buffer.get(i - 1) + value_size); + pointer_type ptr_2 = + reinterpret_cast(buffer.get(i) + value_size); + + for (int j = 0; j < value_count; ++j) { + ptr_2[j] = ptr_2_prev[j]; + } + + ValueJoin::join(m_functor, ptr_2, ptr_1_prev); + } + } - for_loop(par.with(static_chunk_size(1)), 0, num_worker_threads, - [this, &buffer, &bar, num_worker_threads, value_count, - value_size](std::size_t const t) { - reference_type update_sum = ValueInit::init( - m_functor, reinterpret_cast(buffer.get(t))); - - const WorkRange range(m_policy, t, num_worker_threads); - execute_functor_range(m_functor, range.begin(), - range.end(), update_sum, false); - - bar.wait(); - - if (t == 0) { - ValueInit::init(m_functor, reinterpret_cast( - buffer.get(0) + value_size)); - - for (int i = 1; i < num_worker_threads; ++i) { - pointer_type ptr_1_prev = - reinterpret_cast(buffer.get(i - 1)); - pointer_type ptr_2_prev = reinterpret_cast( - buffer.get(i - 1) + value_size); - pointer_type ptr_2 = reinterpret_cast( - buffer.get(i) + value_size); - - for (int j = 0; j < value_count; ++j) { - ptr_2[j] = ptr_2_prev[j]; - } + bar.wait(); - ValueJoin::join(m_functor, ptr_2, ptr_1_prev); - } - } + reference_type update_base = ValueOps::reference( + reinterpret_cast(buffer.get(t) + value_size)); - bar.wait(); + execute_functor_range(m_functor, range.begin(), range.end(), + update_base, true); - reference_type update_base = ValueOps::reference( - reinterpret_cast(buffer.get(t) + value_size)); + num_tasks_remaining.count_down(1); + }); + } - execute_functor_range(m_functor, range.begin(), - range.end(), update_base, true); - }); + num_tasks_remaining.wait(); } inline ParallelScan(const FunctorType &arg_functor, const Policy &arg_policy) @@ -1308,19 +1498,19 @@ public: template class ParallelScanWithTotal, ReturnType, Kokkos::Experimental::HPX> { -private: - using Policy = Kokkos::RangePolicy; - using WorkTag = typename Policy::work_tag; + private: + using Policy = Kokkos::RangePolicy; + using WorkTag = typename Policy::work_tag; using WorkRange = typename Policy::WorkRange; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using Analysis = FunctorAnalysis; - using ValueInit = Kokkos::Impl::FunctorValueInit; - using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; + using ValueInit = Kokkos::Impl::FunctorValueInit; + using ValueJoin = Kokkos::Impl::FunctorValueJoin; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; - using value_type = typename Analysis::value_type; + using value_type = typename Analysis::value_type; const FunctorType m_functor; const Policy m_policy; @@ -1349,88 +1539,95 @@ private: } } -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); - const int value_count = Analysis::value_count(m_functor); + const int value_count = Analysis::value_count(m_functor); const std::size_t value_size = Analysis::value_size(m_functor); thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, 2 * value_size); + using hpx::apply; using hpx::lcos::local::barrier; - using hpx::parallel::for_loop; - using hpx::parallel::execution::par; - using hpx::parallel::execution::static_chunk_size; + using hpx::lcos::local::latch; barrier bar(num_worker_threads); + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &bar, &buffer, &num_tasks_remaining, + num_worker_threads, value_count, value_size, t]() { + reference_type update_sum = ValueInit::init( + m_functor, reinterpret_cast(buffer.get(t))); + + const WorkRange range(m_policy, t, num_worker_threads); + execute_functor_range(m_functor, range.begin(), range.end(), + update_sum, false); + + bar.wait(); + + if (t == 0) { + ValueInit::init(m_functor, reinterpret_cast( + buffer.get(0) + value_size)); + + for (int i = 1; i < num_worker_threads; ++i) { + pointer_type ptr_1_prev = + reinterpret_cast(buffer.get(i - 1)); + pointer_type ptr_2_prev = + reinterpret_cast(buffer.get(i - 1) + value_size); + pointer_type ptr_2 = + reinterpret_cast(buffer.get(i) + value_size); + + for (int j = 0; j < value_count; ++j) { + ptr_2[j] = ptr_2_prev[j]; + } + + ValueJoin::join(m_functor, ptr_2, ptr_1_prev); + } + } - for_loop(par.with(static_chunk_size(1)), 0, num_worker_threads, - [this, &buffer, &bar, num_worker_threads, value_count, - value_size](std::size_t const t) { - reference_type update_sum = ValueInit::init( - m_functor, reinterpret_cast(buffer.get(t))); - - const WorkRange range(m_policy, t, num_worker_threads); - execute_functor_range(m_functor, range.begin(), - range.end(), update_sum, false); - - bar.wait(); - - if (t == 0) { - ValueInit::init(m_functor, reinterpret_cast( - buffer.get(0) + value_size)); - - for (int i = 1; i < num_worker_threads; ++i) { - pointer_type ptr_1_prev = - reinterpret_cast(buffer.get(i - 1)); - pointer_type ptr_2_prev = reinterpret_cast( - buffer.get(i - 1) + value_size); - pointer_type ptr_2 = reinterpret_cast( - buffer.get(i) + value_size); - - for (int j = 0; j < value_count; ++j) { - ptr_2[j] = ptr_2_prev[j]; - } + bar.wait(); - ValueJoin::join(m_functor, ptr_2, ptr_1_prev); - } - } + reference_type update_base = ValueOps::reference( + reinterpret_cast(buffer.get(t) + value_size)); - bar.wait(); + execute_functor_range(m_functor, range.begin(), range.end(), + update_base, true); - reference_type update_base = ValueOps::reference( - reinterpret_cast(buffer.get(t) + value_size)); + if (t == num_worker_threads - 1) { + m_returnvalue = update_base; + } - execute_functor_range(m_functor, range.begin(), - range.end(), update_base, true); + num_tasks_remaining.count_down(1); + }); + } - if (t == std::size_t(num_worker_threads - 1)) { - m_returnvalue = update_base; - } - }); + num_tasks_remaining.wait(); } inline ParallelScanWithTotal(const FunctorType &arg_functor, const Policy &arg_policy, ReturnType &arg_returnvalue) - : m_functor(arg_functor), m_policy(arg_policy), + : m_functor(arg_functor), + m_policy(arg_policy), m_returnvalue(arg_returnvalue) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Impl { template class ParallelFor, Kokkos::Experimental::HPX> { -private: - using Policy = TeamPolicyInternal; + private: + using Policy = TeamPolicyInternal; using WorkTag = typename Policy::work_tag; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using memory_space = Kokkos::HostSpace; const FunctorType m_functor; @@ -1485,7 +1682,7 @@ private: } } -public: + public: void execute() const { dispatch_execute_task(this); } inline void execute_task() const { @@ -1499,42 +1696,66 @@ public: using hpx::parallel::execution::par; using hpx::parallel::execution::static_chunk_size; - for_loop(par.with(static_chunk_size(m_policy.chunk_size())), 0, - m_policy.league_size(), [this, &buffer](const int league_rank) { - execute_functor( - m_functor, m_policy, league_rank, - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), - m_shared); - }); + for_loop( + par.with(static_chunk_size(m_policy.chunk_size())), 0, + m_policy.league_size(), [this, &buffer](const int league_rank) { + execute_functor( + m_functor, m_policy, league_rank, + buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), + m_shared); + }); #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (int league_rank_begin = 0; league_rank_begin < m_policy.league_size(); league_rank_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, league_rank_begin]() { + apply(exec, [this, &buffer, &num_tasks_remaining, league_rank_begin]() { const int league_rank_end = (std::min)( league_rank_begin + m_policy.chunk_size(), m_policy.league_size()); execute_functor_range( m_functor, m_policy, league_rank_begin, league_rank_end, - buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), m_shared); + buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), + m_shared); - sem.signal(1); + num_tasks_remaining.count_down(1); }); - - ++num_tasks; } - sem.wait(num_tasks); + num_tasks_remaining.wait(); + +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), 0, m_policy.league_size(), + m_policy.chunk_size(), [this, &buffer](const int league_rank_begin) { + const int league_rank_end = + (std::min)(league_rank_begin + m_policy.chunk_size(), + m_policy.league_size()); + execute_functor_range( + m_functor, m_policy, league_rank_begin, league_rank_end, + buffer.get(Kokkos::Experimental::HPX::impl_hardware_thread_id()), + m_shared); + }); #endif } ParallelFor(const FunctorType &arg_functor, const Policy &arg_policy) - : m_functor(arg_functor), m_policy(arg_policy), + : m_functor(arg_functor), + m_policy(arg_policy), m_league(arg_policy.league_size()), m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + FunctorTeamShmemSize::value( @@ -1544,11 +1765,11 @@ public: template class ParallelReduce, ReducerType, Kokkos::Experimental::HPX> { -private: + private: using Policy = TeamPolicyInternal; using Analysis = FunctorAnalysis; - using Member = typename Policy::member_type; + using Member = typename Policy::member_type; using WorkTag = typename Policy::work_tag; using ReducerConditional = Kokkos::Impl::if_c::value, @@ -1559,10 +1780,10 @@ private: WorkTag, void>::type; using ValueInit = Kokkos::Impl::FunctorValueInit; using ValueJoin = Kokkos::Impl::FunctorValueJoin; - using ValueOps = Kokkos::Impl::FunctorValueOps; - using pointer_type = typename Analysis::pointer_type; + using ValueOps = Kokkos::Impl::FunctorValueOps; + using pointer_type = typename Analysis::pointer_type; using reference_type = typename Analysis::reference_type; - using value_type = typename Analysis::value_type; + using value_type = typename Analysis::value_type; const FunctorType m_functor; const int m_league; @@ -1628,10 +1849,8 @@ private: } } -public: - void execute() const { - dispatch_execute_task(this); - } + public: + void execute() const { dispatch_execute_task(this); } inline void execute_task() const { const int num_worker_threads = Kokkos::Experimental::HPX::concurrency(); @@ -1641,15 +1860,15 @@ public: thread_buffer &buffer = Kokkos::Experimental::HPX::impl_get_buffer(); buffer.resize(num_worker_threads, value_size + m_shared); +#if KOKKOS_HPX_IMPLEMENTATION == 0 using hpx::parallel::for_loop; using hpx::parallel::execution::par; - for_loop(par, 0, num_worker_threads, [this, &buffer](std::size_t t) { + for_loop(par, 0, num_worker_threads, [this, &buffer](const std::size_t t) { ValueInit::init(ReducerConditional::select(m_functor, m_reducer), reinterpret_cast(buffer.get(t))); }); -#if KOKKOS_HPX_IMPLEMENTATION == 0 using hpx::parallel::execution::static_chunk_size; hpx::parallel::for_loop( @@ -1667,14 +1886,33 @@ public: #elif KOKKOS_HPX_IMPLEMENTATION == 1 using hpx::apply; - using hpx::lcos::local::counting_semaphore; + using hpx::lcos::local::latch; - counting_semaphore sem(0); - std::size_t num_tasks = 0; + { + latch num_tasks_remaining(num_worker_threads); + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for (int t = 0; t < num_worker_threads; ++t) { + apply(exec, [this, &buffer, &num_tasks_remaining, t]() { + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + + num_tasks_remaining.count_down(1); + }); + } + + num_tasks_remaining.wait(); + } + + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + latch num_tasks_remaining(num_tasks); + ChunkedRoundRobinExecutor exec(num_tasks); for (int league_rank_begin = 0; league_rank_begin < m_policy.league_size(); league_rank_begin += m_policy.chunk_size()) { - apply([this, &buffer, &sem, league_rank_begin, value_size]() { + apply(exec, [this, &buffer, &num_tasks_remaining, league_rank_begin, + value_size]() { std::size_t t = Kokkos::Experimental::HPX::impl_hardware_thread_id(); reference_type update = ValueOps::reference(reinterpret_cast(buffer.get(t))); @@ -1684,13 +1922,47 @@ public: m_functor, m_policy, league_rank_begin, league_rank_end, buffer.get(t) + value_size, m_shared, update); - sem.signal(1); + num_tasks_remaining.count_down(1); }); + } + + num_tasks_remaining.wait(); - ++num_tasks; +#elif KOKKOS_HPX_IMPLEMENTATION == 2 + using hpx::parallel::for_loop; + using hpx::parallel::for_loop_strided; + using hpx::parallel::execution::par; + using hpx::parallel::execution::static_chunk_size; + + { + ChunkedRoundRobinExecutor exec(num_worker_threads); + + for_loop(par.on(exec).with(static_chunk_size(1)), 0, num_worker_threads, + [this, &buffer](std::size_t const t) { + ValueInit::init( + ReducerConditional::select(m_functor, m_reducer), + reinterpret_cast(buffer.get(t))); + }); } - sem.wait(num_tasks); + const int num_tasks = (m_policy.league_size() + m_policy.chunk_size() - 1) / + m_policy.chunk_size(); + ChunkedRoundRobinExecutor exec(num_tasks); + + for_loop_strided( + par.on(exec).with(static_chunk_size(1)), 0, m_policy.league_size(), + m_policy.chunk_size(), + [this, &buffer, value_size](int const league_rank_begin) { + std::size_t t = Kokkos::Experimental::HPX::impl_hardware_thread_id(); + reference_type update = ValueOps::reference( + reinterpret_cast(buffer.get(t))); + const int league_rank_end = + (std::min)(league_rank_begin + m_policy.chunk_size(), + m_policy.league_size()); + execute_functor_range( + m_functor, m_policy, league_rank_begin, league_rank_end, + buffer.get(t) + value_size, m_shared, update); + }); #endif const pointer_type ptr = reinterpret_cast(buffer.get(0)); @@ -1719,8 +1991,10 @@ public: typename std::enable_if::value && !Kokkos::is_reducer_type::value, void *>::type = NULL) - : m_functor(arg_functor), m_league(arg_policy.league_size()), - m_policy(arg_policy), m_reducer(InvalidType()), + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_policy(arg_policy), + m_reducer(InvalidType()), m_result_ptr(arg_result.data()), m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + FunctorTeamShmemSize::value( @@ -1729,16 +2003,18 @@ public: inline ParallelReduce(const FunctorType &arg_functor, Policy arg_policy, const ReducerType &reducer) - : m_functor(arg_functor), m_league(arg_policy.league_size()), - m_policy(arg_policy), m_reducer(reducer), + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_policy(arg_policy), + m_reducer(reducer), m_result_ptr(reducer.view().data()), m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + FunctorTeamShmemSize::value( arg_functor, arg_policy.team_size())), m_force_synchronous(!reducer.view().impl_track().has_record()) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { @@ -1796,14 +2072,14 @@ KOKKOS_INLINE_FUNCTION } KOKKOS_INLINE_FUNCTION -Impl::ThreadSingleStruct -PerTeam(const Impl::HPXTeamMember &thread) { +Impl::ThreadSingleStruct PerTeam( + const Impl::HPXTeamMember &thread) { return Impl::ThreadSingleStruct(thread); } KOKKOS_INLINE_FUNCTION -Impl::VectorSingleStruct -PerThread(const Impl::HPXTeamMember &thread) { +Impl::VectorSingleStruct PerThread( + const Impl::HPXTeamMember &thread) { return Impl::VectorSingleStruct(thread); } @@ -1950,7 +2226,7 @@ KOKKOS_INLINE_FUNCTION void parallel_scan( &loop_boundaries, const FunctorType &lambda) { using ValueTraits = Kokkos::Impl::FunctorValueTraits; - using value_type = typename ValueTraits::value_type; + using value_type = typename ValueTraits::value_type; value_type scan_val = value_type(); @@ -1964,34 +2240,34 @@ KOKKOS_INLINE_FUNCTION void parallel_scan( } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::VectorSingleStruct &single_struct, - const FunctorType &lambda) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct &single_struct, + const FunctorType &lambda) { lambda(); } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::ThreadSingleStruct &single_struct, - const FunctorType &lambda) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct &single_struct, + const FunctorType &lambda) { lambda(); } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::VectorSingleStruct &single_struct, - const FunctorType &lambda, ValueType &val) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::VectorSingleStruct &single_struct, + const FunctorType &lambda, ValueType &val) { lambda(val); } template -KOKKOS_INLINE_FUNCTION void -single(const Impl::ThreadSingleStruct &single_struct, - const FunctorType &lambda, ValueType &val) { +KOKKOS_INLINE_FUNCTION void single( + const Impl::ThreadSingleStruct &single_struct, + const FunctorType &lambda, ValueType &val) { lambda(val); } -} // namespace Kokkos +} // namespace Kokkos #include diff --git a/lib/kokkos/core/src/Kokkos_HostSpace.hpp b/lib/kokkos/core/src/Kokkos_HostSpace.hpp index 06ccf63987..974ca1e5ef 100644 --- a/lib/kokkos/core/src/Kokkos_HostSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_HostSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -73,10 +74,10 @@ namespace Impl { /// This function initializes the locks to zero (unset). void init_lock_array_host_space(); -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. bool lock_address_host_space(void* ptr); @@ -84,13 +85,13 @@ bool lock_address_host_space(void* ptr); /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -void unlock_address_host_space( void* ptr ); +void unlock_address_host_space(void* ptr); -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos namespace Kokkos { @@ -100,10 +101,10 @@ namespace Kokkos { /// HostSpace is a memory space that governs host memory. "Host" /// memory means the usual CPU-accessible memory. class HostSpace { -public: + public: //! Tag this class as a kokkos memory space - typedef HostSpace memory_space; - typedef size_t size_type; + typedef HostSpace memory_space; + typedef size_t size_type; /// \typedef execution_space /// \brief Default execution space for this memory space. @@ -111,63 +112,68 @@ public: /// Every memory space has a default execution space. This is /// useful for things like initializing a View (which happens in /// parallel using the View's default execution space). -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) - typedef Kokkos::Threads execution_space; -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) + typedef Kokkos::Threads execution_space; +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) typedef Kokkos::Experimental::HPX execution_space; //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_OPENMP ) - typedef Kokkos::OpenMP execution_space; -#elif defined( KOKKOS_ENABLE_THREADS ) - typedef Kokkos::Threads execution_space; +#elif defined(KOKKOS_ENABLE_OPENMP) + typedef Kokkos::OpenMP execution_space; +#elif defined(KOKKOS_ENABLE_THREADS) + typedef Kokkos::Threads execution_space; //#elif defined( KOKKOS_ENABLE_QTHREADS ) // typedef Kokkos::Qthreads execution_space; -#elif defined( KOKKOS_ENABLE_HPX ) +#elif defined(KOKKOS_ENABLE_HPX) typedef Kokkos::Experimental::HPX execution_space; -#elif defined( KOKKOS_ENABLE_SERIAL ) - typedef Kokkos::Serial execution_space; +#elif defined(KOKKOS_ENABLE_SERIAL) + typedef Kokkos::Serial execution_space; #else -# error "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." +#error \ + "At least one of the following host execution spaces must be defined: Kokkos::OpenMP, Kokkos::Threads, Kokkos::Qthreads, or Kokkos::Serial. You might be seeing this message if you disabled the Kokkos::Serial device explicitly using the Kokkos_ENABLE_Serial:BOOL=OFF CMake option, but did not enable any of the other host execution space devices." #endif //! This memory space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; /**\brief Default memory space instance */ HostSpace(); - HostSpace( HostSpace && rhs ) = default; - HostSpace( const HostSpace & rhs ) = default; - HostSpace & operator = ( HostSpace && ) = default; - HostSpace & operator = ( const HostSpace & ) = default; - ~HostSpace() = default; + HostSpace(HostSpace&& rhs) = default; + HostSpace(const HostSpace& rhs) = default; + HostSpace& operator=(HostSpace&&) = default; + HostSpace& operator=(const HostSpace&) = default; + ~HostSpace() = default; - /**\brief Non-default memory space instance to choose allocation mechansim, if available */ + /**\brief Non-default memory space instance to choose allocation mechansim, + * if available */ - enum AllocationMechanism { STD_MALLOC, POSIX_MEMALIGN, POSIX_MMAP, INTEL_MM_ALLOC }; + enum AllocationMechanism { + STD_MALLOC, + POSIX_MEMALIGN, + POSIX_MMAP, + INTEL_MM_ALLOC + }; - explicit - HostSpace( const AllocationMechanism & ); + explicit HostSpace(const AllocationMechanism&); /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; } -private: - AllocationMechanism m_alloc_mech; + private: + AllocationMechanism m_alloc_mech; static constexpr const char* m_name = "Host"; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::HostSpace, void >; + friend class Kokkos::Impl::SharedAllocationRecord; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -175,38 +181,45 @@ namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::HostSpace, Kokkos::HostSpace >::assignable, "" ); +static_assert(Kokkos::Impl::MemorySpaceAccess::assignable, + ""); -template< typename S > +template struct HostMirror { -private: + private: // If input execution space can access HostSpace then keep it. // Example: Kokkos::OpenMP can access, Kokkos::Cuda cannot - enum { keep_exe = Kokkos::Impl::MemorySpaceAccess - < typename S::execution_space::memory_space, Kokkos::HostSpace >::accessible }; + enum { + keep_exe = Kokkos::Impl::MemorySpaceAccess< + typename S::execution_space::memory_space, + Kokkos::HostSpace>::accessible + }; // If HostSpace can access memory space then keep it. // Example: Cannot access Kokkos::CudaSpace, can access Kokkos::CudaUVMSpace - enum { keep_mem = Kokkos::Impl::MemorySpaceAccess - < Kokkos::HostSpace, typename S::memory_space >::accessible }; - -public: - - typedef typename std::conditional - < keep_exe && keep_mem /* Can keep whole space */ - , S - , typename std::conditional - < keep_mem /* Can keep memory space, use default Host execution space */ - , Kokkos::Device< Kokkos::HostSpace::execution_space - , typename S::memory_space > - , Kokkos::HostSpace - >::type - >::type Space; + enum { + keep_mem = + Kokkos::Impl::MemorySpaceAccess::accessible + }; + + public: + typedef typename std::conditional< + keep_exe && keep_mem /* Can keep whole space */ + , + S, + typename std::conditional< + keep_mem /* Can keep memory space, use default Host execution space */ + , + Kokkos::Device, + Kokkos::HostSpace>::type>::type Space; }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -214,19 +227,18 @@ namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::HostSpace, void > - : public SharedAllocationRecord< void, void > -{ -private: +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: friend Kokkos::HostSpace; - typedef SharedAllocationRecord< void, void > RecordBase; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG /**\brief Root record for tracked allocations from this HostSpace instance */ @@ -235,61 +247,51 @@ private: const Kokkos::HostSpace m_space; -protected: + protected: ~SharedAllocationRecord(); SharedAllocationRecord() = default; - SharedAllocationRecord( const Kokkos::HostSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::HostSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: - - inline - std::string get_label() const - { - return std::string( RecordBase::head()->m_label ); + public: + inline std::string get_label() const { + return std::string(RecordBase::head()->m_label); } - KOKKOS_INLINE_FUNCTION static - SharedAllocationRecord * allocate( const Kokkos::HostSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ) - { -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) - return new SharedAllocationRecord( arg_space, arg_label, arg_alloc_size ); + KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate( + const Kokkos::HostSpace& arg_space, const std::string& arg_label, + const size_t arg_alloc_size) { +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) + return new SharedAllocationRecord(arg_space, arg_label, arg_alloc_size); #else - return (SharedAllocationRecord *) 0; + return (SharedAllocationRecord*)0; #endif } - /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::HostSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked(const Kokkos::HostSpace& arg_space, + const std::string& arg_label, + const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream &, const Kokkos::HostSpace &, bool detail = false ); + static void print_records(std::ostream&, const Kokkos::HostSpace&, + bool detail = false); }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -297,24 +299,21 @@ namespace Kokkos { namespace Impl { -#define PAR_DEEP_COPY_USE_MEMCPY - -template< class ExecutionSpace > -struct DeepCopy< HostSpace, HostSpace, ExecutionSpace > { - DeepCopy( void * dst, const void * src, size_t n ) { - hostspace_parallel_deepcopy(dst,src,n); +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + hostspace_parallel_deepcopy(dst, src, n); } - DeepCopy( const ExecutionSpace& exec, void * dst, const void * src, size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - hostspace_parallel_deepcopy(dst,src,n); + hostspace_parallel_deepcopy(dst, src, n); exec.fence(); } }; -} // namespace Impl - -} // namespace Kokkos +} // namespace Impl -#endif // #define KOKKOS_HOSTSPACE_HPP +} // namespace Kokkos +#endif // #define KOKKOS_HOSTSPACE_HPP diff --git a/lib/kokkos/core/src/Kokkos_Layout.hpp b/lib/kokkos/core/src/Kokkos_Layout.hpp index 6f423d545f..d34bdb9150 100644 --- a/lib/kokkos/core/src/Kokkos_Layout.hpp +++ b/lib/kokkos/core/src/Kokkos_Layout.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -72,22 +73,22 @@ enum { ARRAY_LAYOUT_MAX_RANK = 8 }; /// major." struct LayoutLeft { //! Tag this class as a kokkos array layout - typedef LayoutLeft array_layout ; + typedef LayoutLeft array_layout; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ]; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutLeft( LayoutLeft const & ) = default ; - LayoutLeft( LayoutLeft && ) = default ; - LayoutLeft & operator = ( LayoutLeft const & ) = default ; - LayoutLeft & operator = ( LayoutLeft && ) = default ; + LayoutLeft(LayoutLeft const&) = default; + LayoutLeft(LayoutLeft&&) = default; + LayoutLeft& operator=(LayoutLeft const&) = default; + LayoutLeft& operator=(LayoutLeft&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutLeft( size_t N0 = 0 , size_t N1 = 0 , size_t N2 = 0 , size_t N3 = 0 - , size_t N4 = 0 , size_t N5 = 0 , size_t N6 = 0 , size_t N7 = 0 ) - : dimension { N0 , N1 , N2 , N3 , N4 , N5 , N6 , N7 } {} + explicit constexpr LayoutLeft(size_t N0 = 0, size_t N1 = 0, size_t N2 = 0, + size_t N3 = 0, size_t N4 = 0, size_t N5 = 0, + size_t N6 = 0, size_t N7 = 0) + : dimension{N0, N1, N2, N3, N4, N5, N6, N7} {} }; //---------------------------------------------------------------------------- @@ -106,22 +107,22 @@ struct LayoutLeft { /// two-dimensional array, "layout right" is also called "row major." struct LayoutRight { //! Tag this class as a kokkos array layout - typedef LayoutRight array_layout ; + typedef LayoutRight array_layout; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ]; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutRight( LayoutRight const & ) = default ; - LayoutRight( LayoutRight && ) = default ; - LayoutRight & operator = ( LayoutRight const & ) = default ; - LayoutRight & operator = ( LayoutRight && ) = default ; + LayoutRight(LayoutRight const&) = default; + LayoutRight(LayoutRight&&) = default; + LayoutRight& operator=(LayoutRight const&) = default; + LayoutRight& operator=(LayoutRight&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutRight( size_t N0 = 0 , size_t N1 = 0 , size_t N2 = 0 , size_t N3 = 0 - , size_t N4 = 0 , size_t N5 = 0 , size_t N6 = 0 , size_t N7 = 0 ) - : dimension { N0 , N1 , N2 , N3 , N4 , N5 , N6 , N7 } {} + explicit constexpr LayoutRight(size_t N0 = 0, size_t N1 = 0, size_t N2 = 0, + size_t N3 = 0, size_t N4 = 0, size_t N5 = 0, + size_t N6 = 0, size_t N7 = 0) + : dimension{N0, N1, N2, N3, N4, N5, N6, N7} {} }; //---------------------------------------------------------------------------- @@ -129,19 +130,18 @@ struct LayoutRight { /// \brief Memory layout tag indicated arbitrarily strided /// multi-index mapping into contiguous memory. struct LayoutStride { - //! Tag this class as a kokkos array layout - typedef LayoutStride array_layout ; + typedef LayoutStride array_layout; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ] ; - size_t stride[ ARRAY_LAYOUT_MAX_RANK ] ; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; + size_t stride[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = false }; - LayoutStride( LayoutStride const & ) = default ; - LayoutStride( LayoutStride && ) = default ; - LayoutStride & operator = ( LayoutStride const & ) = default ; - LayoutStride & operator = ( LayoutStride && ) = default ; + LayoutStride(LayoutStride const&) = default; + LayoutStride(LayoutStride&&) = default; + LayoutStride& operator=(LayoutStride const&) = default; + LayoutStride& operator=(LayoutStride&&) = default; /** \brief Compute strides from ordered dimensions. * @@ -150,47 +150,40 @@ struct LayoutStride { * Order = {0,1,2,...} is LayoutLeft * Order = {...,2,1,0} is LayoutRight */ - template< typename iTypeOrder , typename iTypeDimen > - KOKKOS_INLINE_FUNCTION static - LayoutStride order_dimensions( int const rank - , iTypeOrder const * const order - , iTypeDimen const * const dimen ) - { - LayoutStride tmp ; - // Verify valid rank order: - int check_input = ARRAY_LAYOUT_MAX_RANK < rank ? 0 : int( 1 << rank ) - 1 ; - for ( int r = 0 ; r < ARRAY_LAYOUT_MAX_RANK ; ++r ) { - tmp.dimension[r] = 0 ; - tmp.stride[r] = 0 ; - } - for ( int r = 0 ; r < rank ; ++r ) { - check_input &= ~int( 1 << order[r] ); - } - if ( 0 == check_input ) { - size_t n = 1 ; - for ( int r = 0 ; r < rank ; ++r ) { - tmp.stride[ order[r] ] = n ; - n *= ( dimen[order[r]] ); - tmp.dimension[r] = dimen[r]; - } + template + KOKKOS_INLINE_FUNCTION static LayoutStride order_dimensions( + int const rank, iTypeOrder const* const order, + iTypeDimen const* const dimen) { + LayoutStride tmp; + // Verify valid rank order: + int check_input = ARRAY_LAYOUT_MAX_RANK < rank ? 0 : int(1 << rank) - 1; + for (int r = 0; r < ARRAY_LAYOUT_MAX_RANK; ++r) { + tmp.dimension[r] = 0; + tmp.stride[r] = 0; + } + for (int r = 0; r < rank; ++r) { + check_input &= ~int(1 << order[r]); + } + if (0 == check_input) { + size_t n = 1; + for (int r = 0; r < rank; ++r) { + tmp.stride[order[r]] = n; + n *= (dimen[order[r]]); + tmp.dimension[r] = dimen[r]; } - return tmp ; } + return tmp; + } KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutStride( size_t N0 = 0 , size_t S0 = 0 - , size_t N1 = 0 , size_t S1 = 0 - , size_t N2 = 0 , size_t S2 = 0 - , size_t N3 = 0 , size_t S3 = 0 - , size_t N4 = 0 , size_t S4 = 0 - , size_t N5 = 0 , size_t S5 = 0 - , size_t N6 = 0 , size_t S6 = 0 - , size_t N7 = 0 , size_t S7 = 0 - ) - : dimension { N0 , N1 , N2 , N3 , N4 , N5 , N6 , N7 } - , stride { S0 , S1 , S2 , S3 , S4 , S5 , S6 , S7 } - {} + explicit constexpr LayoutStride(size_t N0 = 0, size_t S0 = 0, size_t N1 = 0, + size_t S1 = 0, size_t N2 = 0, size_t S2 = 0, + size_t N3 = 0, size_t S3 = 0, size_t N4 = 0, + size_t S4 = 0, size_t N5 = 0, size_t S5 = 0, + size_t N6 = 0, size_t S6 = 0, size_t N7 = 0, + size_t S7 = 0) + : dimension{N0, N1, N2, N3, N4, N5, N6, N7}, stride{S0, S1, S2, S3, + S4, S5, S6, S7} {} }; // ========================================================================== @@ -213,81 +206,81 @@ struct LayoutStride { /// compile-time constants. This speeds up index calculations. If /// both tile dimensions are powers of two, Kokkos can optimize /// further. -template < unsigned ArgN0 , unsigned ArgN1 , - bool IsPowerOfTwo = ( Impl::is_integral_power_of_two(ArgN0) && - Impl::is_integral_power_of_two(ArgN1) ) - > +template struct LayoutTileLeft { - - static_assert( Impl::is_integral_power_of_two(ArgN0) && - Impl::is_integral_power_of_two(ArgN1) - , "LayoutTileLeft must be given power-of-two tile dimensions" ); + static_assert(Impl::is_integral_power_of_two(ArgN0) && + Impl::is_integral_power_of_two(ArgN1), + "LayoutTileLeft must be given power-of-two tile dimensions"); //! Tag this class as a kokkos array layout - typedef LayoutTileLeft array_layout ; + typedef LayoutTileLeft array_layout; enum { N0 = ArgN0 }; enum { N1 = ArgN1 }; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ] ; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutTileLeft( LayoutTileLeft const & ) = default ; - LayoutTileLeft( LayoutTileLeft && ) = default ; - LayoutTileLeft & operator = ( LayoutTileLeft const & ) = default ; - LayoutTileLeft & operator = ( LayoutTileLeft && ) = default ; + LayoutTileLeft(LayoutTileLeft const&) = default; + LayoutTileLeft(LayoutTileLeft&&) = default; + LayoutTileLeft& operator=(LayoutTileLeft const&) = default; + LayoutTileLeft& operator=(LayoutTileLeft&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutTileLeft( size_t argN0 = 0 , size_t argN1 = 0 , size_t argN2 = 0 , size_t argN3 = 0 - , size_t argN4 = 0 , size_t argN5 = 0 , size_t argN6 = 0 , size_t argN7 = 0 - ) - : dimension { argN0 , argN1 , argN2 , argN3 , argN4 , argN5 , argN6 , argN7 } {} + explicit constexpr LayoutTileLeft(size_t argN0 = 0, size_t argN1 = 0, + size_t argN2 = 0, size_t argN3 = 0, + size_t argN4 = 0, size_t argN5 = 0, + size_t argN6 = 0, size_t argN7 = 0) + : dimension{argN0, argN1, argN2, argN3, argN4, argN5, argN6, argN7} {} }; -#endif // KOKKOS_ENABLE_DEPRECATED_CODE +#endif // KOKKOS_ENABLE_DEPRECATED_CODE // =================================================================================== ////////////////////////////////////////////////////////////////////////////////////// -enum class Iterate -{ +enum class Iterate { Default, - Left, // Left indices stride fastest - Right // Right indices stride fastest + Left, // Left indices stride fastest + Right // Right indices stride fastest }; // To check for LayoutTiled -// This is to hide extra compile-time 'identifier' info within the LayoutTiled class by not relying on template specialization to include the ArgN*'s -template < typename LayoutTiledCheck, class Enable = void > +// This is to hide extra compile-time 'identifier' info within the LayoutTiled +// class by not relying on template specialization to include the ArgN*'s +template struct is_layouttiled : std::false_type {}; #ifndef KOKKOS_ENABLE_DEPRECATED_CODE -template < typename LayoutTiledCheck > -struct is_layouttiled< LayoutTiledCheck, typename std::enable_if::type > : std::true_type {}; +template +struct is_layouttiled< + LayoutTiledCheck, + typename std::enable_if::type> + : std::true_type {}; namespace Experimental { /// LayoutTiled // Must have Rank >= 2 -template < Kokkos::Iterate OuterP, Kokkos::Iterate InnerP, - unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 = 0, unsigned ArgN3 = 0, unsigned ArgN4 = 0, unsigned ArgN5 = 0, unsigned ArgN6 = 0, unsigned ArgN7 = 0, - bool IsPowerOfTwo = - ( Kokkos::Impl::is_integral_power_of_two(ArgN0) && - Kokkos::Impl::is_integral_power_of_two(ArgN1) && - (Kokkos::Impl::is_integral_power_of_two(ArgN2) || (ArgN2 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN3) || (ArgN3 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN4) || (ArgN4 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN5) || (ArgN5 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN6) || (ArgN6 == 0) ) && - (Kokkos::Impl::is_integral_power_of_two(ArgN7) || (ArgN7 == 0) ) - ) - > +template < + Kokkos::Iterate OuterP, Kokkos::Iterate InnerP, unsigned ArgN0, + unsigned ArgN1, unsigned ArgN2 = 0, unsigned ArgN3 = 0, unsigned ArgN4 = 0, + unsigned ArgN5 = 0, unsigned ArgN6 = 0, unsigned ArgN7 = 0, + bool IsPowerOfTwo = + (Kokkos::Impl::is_integral_power_of_two(ArgN0) && + Kokkos::Impl::is_integral_power_of_two(ArgN1) && + (Kokkos::Impl::is_integral_power_of_two(ArgN2) || (ArgN2 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN3) || (ArgN3 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN4) || (ArgN4 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN5) || (ArgN5 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN6) || (ArgN6 == 0)) && + (Kokkos::Impl::is_integral_power_of_two(ArgN7) || (ArgN7 == 0)))> struct LayoutTiled { - - static_assert( IsPowerOfTwo - , "LayoutTiled must be given power-of-two tile dimensions" ); + static_assert(IsPowerOfTwo, + "LayoutTiled must be given power-of-two tile dimensions"); #if 0 static_assert( (Impl::is_integral_power_of_two(ArgN0) ) && @@ -301,7 +294,9 @@ struct LayoutTiled { , "LayoutTiled must be given power-of-two tile dimensions" ); #endif - typedef LayoutTiled array_layout ; + typedef LayoutTiled + array_layout; static constexpr Iterate outer_pattern = OuterP; static constexpr Iterate inner_pattern = InnerP; @@ -314,79 +309,93 @@ struct LayoutTiled { enum { N6 = ArgN6 }; enum { N7 = ArgN7 }; - size_t dimension[ ARRAY_LAYOUT_MAX_RANK ] ; + size_t dimension[ARRAY_LAYOUT_MAX_RANK]; enum { is_extent_constructible = true }; - LayoutTiled( LayoutTiled const & ) = default ; - LayoutTiled( LayoutTiled && ) = default ; - LayoutTiled & operator = ( LayoutTiled const & ) = default ; - LayoutTiled & operator = ( LayoutTiled && ) = default ; + LayoutTiled(LayoutTiled const&) = default; + LayoutTiled(LayoutTiled&&) = default; + LayoutTiled& operator=(LayoutTiled const&) = default; + LayoutTiled& operator=(LayoutTiled&&) = default; KOKKOS_INLINE_FUNCTION - explicit constexpr - LayoutTiled( size_t argN0 = 0 , size_t argN1 = 0 , size_t argN2 = 0 , size_t argN3 = 0 - , size_t argN4 = 0 , size_t argN5 = 0 , size_t argN6 = 0 , size_t argN7 = 0 - ) - : dimension { argN0 , argN1 , argN2 , argN3 , argN4 , argN5 , argN6 , argN7 } {} + explicit constexpr LayoutTiled(size_t argN0 = 0, size_t argN1 = 0, + size_t argN2 = 0, size_t argN3 = 0, + size_t argN4 = 0, size_t argN5 = 0, + size_t argN6 = 0, size_t argN7 = 0) + : dimension{argN0, argN1, argN2, argN3, argN4, argN5, argN6, argN7} {} }; -} // namespace Experimental +} // namespace Experimental #endif - // For use with view_copy -template < typename ... Layout > +template struct layout_iterate_type_selector { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Default ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Default ; + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::Iterate::Default; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::Iterate::Default; }; template <> -struct layout_iterate_type_selector< Kokkos::LayoutRight > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right ; +struct layout_iterate_type_selector { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right; }; template <> -struct layout_iterate_type_selector< Kokkos::LayoutLeft > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left ; +struct layout_iterate_type_selector { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left; }; template <> -struct layout_iterate_type_selector< Kokkos::LayoutStride > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Default ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Default ; +struct layout_iterate_type_selector { + static const Kokkos::Iterate outer_iteration_pattern = + Kokkos::Iterate::Default; + static const Kokkos::Iterate inner_iteration_pattern = + Kokkos::Iterate::Default; }; #ifndef KOKKOS_ENABLE_DEPRECATED_CODE -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left; }; -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Left; }; -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Left; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right; }; -template < unsigned ArgN0 , unsigned ArgN1 , unsigned ArgN2 , unsigned ArgN3 , unsigned ArgN4 , unsigned ArgN5 , unsigned ArgN6 , unsigned ArgN7 > -struct layout_iterate_type_selector< Kokkos::Experimental::LayoutTiled > { - static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right ; - static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right ; +template +struct layout_iterate_type_selector > { + static const Kokkos::Iterate outer_iteration_pattern = Kokkos::Iterate::Right; + static const Kokkos::Iterate inner_iteration_pattern = Kokkos::Iterate::Right; }; #endif -} // namespace Kokkos - -#endif // #ifndef KOKKOS_LAYOUT_HPP +} // namespace Kokkos +#endif // #ifndef KOKKOS_LAYOUT_HPP diff --git a/lib/kokkos/core/src/Kokkos_Macros.hpp b/lib/kokkos/core/src/Kokkos_Macros.hpp index 6b8ae02f82..5649d12e97 100644 --- a/lib/kokkos/core/src/Kokkos_Macros.hpp +++ b/lib/kokkos/core/src/Kokkos_Macros.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -52,15 +53,16 @@ * KOKKOS_ENABLE_QTHREADS Kokkos::Qthreads execution space * KOKKOS_ENABLE_HPX Kokkos::Experimental::HPX execution space * KOKKOS_ENABLE_OPENMP Kokkos::OpenMP execution space - * KOKKOS_ENABLE_OPENMPTARGET Kokkos::Experimental::OpenMPTarget execution space - * KOKKOS_ENABLE_HWLOC HWLOC library is available. + * KOKKOS_ENABLE_OPENMPTARGET Kokkos::Experimental::OpenMPTarget + * execution space KOKKOS_ENABLE_HWLOC HWLOC library is available. * KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK Insert array bounds checks, is expensive! - * KOKKOS_ENABLE_MPI Negotiate MPI/execution space interactions. - * KOKKOS_ENABLE_CUDA_UVM Use CUDA UVM for Cuda memory space. + * KOKKOS_ENABLE_MPI Negotiate MPI/execution space + * interactions. KOKKOS_ENABLE_CUDA_UVM Use CUDA UVM for Cuda memory + * space. */ #ifndef KOKKOS_DONT_INCLUDE_CORE_CONFIG_H - #include +#include #endif #include @@ -97,449 +99,461 @@ //---------------------------------------------------------------------------- -#if defined(KOKKOS_ENABLE_SERIAL) || defined(KOKKOS_ENABLE_THREADS) || \ +#if defined(KOKKOS_ENABLE_SERIAL) || defined(KOKKOS_ENABLE_THREADS) || \ defined(KOKKOS_ENABLE_OPENMP) || defined(KOKKOS_ENABLE_QTHREADS) || \ - defined(KOKKOS_ENABLE_HPX) || \ - defined(KOKKOS_ENABLE_ROCM) || defined(KOKKOS_ENABLE_OPENMPTARGET) - #define KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND + defined(KOKKOS_ENABLE_HPX) || defined(KOKKOS_ENABLE_ROCM) || \ + defined(KOKKOS_ENABLE_OPENMPTARGET) +#define KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND #endif -#if !defined(KOKKOS_ENABLE_THREADS) && !defined(KOKKOS_ENABLE_CUDA) && \ +#if !defined(KOKKOS_ENABLE_THREADS) && !defined(KOKKOS_ENABLE_CUDA) && \ !defined(KOKKOS_ENABLE_OPENMP) && !defined(KOKKOS_ENABLE_QTHREADS) && \ - !defined(KOKKOS_ENABLE_HPX) && \ - !defined(KOKKOS_ENABLE_ROCM) && !defined(KOKKOS_ENABLE_OPENMPTARGET) - #define KOKKOS_INTERNAL_NOT_PARALLEL + !defined(KOKKOS_ENABLE_HPX) && !defined(KOKKOS_ENABLE_ROCM) && \ + !defined(KOKKOS_ENABLE_OPENMPTARGET) +#define KOKKOS_INTERNAL_NOT_PARALLEL #endif #define KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA -#if defined( KOKKOS_ENABLE_CUDA ) && defined( __CUDACC__ ) - // Compiling with a CUDA compiler. - // - // Include to pick up the CUDA_VERSION macro defined as: - // CUDA_VERSION = ( MAJOR_VERSION * 1000 ) + ( MINOR_VERSION * 10 ) - // - // When generating device code the __CUDA_ARCH__ macro is defined as: - // __CUDA_ARCH__ = ( MAJOR_CAPABILITY * 100 ) + ( MINOR_CAPABILITY * 10 ) - - #include - #include - - #if !defined( CUDA_VERSION ) - #error "#include did not define CUDA_VERSION." - #endif - - #if ( CUDA_VERSION < 7000 ) - // CUDA supports C++11 in device code starting with version 7.0. - // This includes auto type and device code internal lambdas. - #error "Cuda version 7.0 or greater required." - #endif - - #if defined( __CUDA_ARCH__ ) && ( __CUDA_ARCH__ < 300 ) - // Compiling with CUDA compiler for device code. - #error "Cuda device capability >= 3.0 is required." - #endif - - #ifdef KOKKOS_ENABLE_CUDA_LAMBDA - #if ( CUDA_VERSION < 7050 ) - // CUDA supports C++11 lambdas generated in host code to be given - // to the device starting with version 7.5. But the release candidate (7.5.6) - // still identifies as 7.0. - #error "Cuda version 7.5 or greater required for host-to-device Lambda support." - #endif - - #if ( CUDA_VERSION < 8000 ) && defined( __NVCC__ ) - #define KOKKOS_LAMBDA [=]__device__ - #if defined( KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND ) - #undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA - #endif - #else - #define KOKKOS_LAMBDA [=]__host__ __device__ - - #if defined( KOKKOS_ENABLE_CXX17 ) || defined( KOKKOS_ENABLE_CXX20 ) - #define KOKKOS_CLASS_LAMBDA [=,*this] __host__ __device__ - #endif - #endif - - #if defined( __NVCC__ ) - #define KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER - #endif - #else // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) - #undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA - #endif // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) - - #if ( 9000 <= CUDA_VERSION ) && ( CUDA_VERSION < 10000 ) - // CUDA 9 introduced an incorrect warning, - // see https://github.com/kokkos/kokkos/issues/1470 - #define KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - #endif - - #if ( 10000 > CUDA_VERSION ) - #define KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API - #endif - - #if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 700) - // PTX atomics with memory order semantics are only available on volta and later - #if !defined(KOKKOS_DISABLE_CUDA_ASM) - #if !defined(KOKKOS_ENABLE_CUDA_ASM) - #define KOKKOS_ENABLE_CUDA_ASM - #if !defined(KOKKOS_DISABLE_CUDA_ASM_ATOMICS) - #define KOKKOS_ENABLE_CUDA_ASM_ATOMICS - #endif - #endif - #endif - #endif - - -#endif // #if defined( KOKKOS_ENABLE_CUDA ) && defined( __CUDACC__ ) +#if defined(KOKKOS_ENABLE_CUDA) && defined(__CUDACC__) +// Compiling with a CUDA compiler. +// +// Include to pick up the CUDA_VERSION macro defined as: +// CUDA_VERSION = ( MAJOR_VERSION * 1000 ) + ( MINOR_VERSION * 10 ) +// +// When generating device code the __CUDA_ARCH__ macro is defined as: +// __CUDA_ARCH__ = ( MAJOR_CAPABILITY * 100 ) + ( MINOR_CAPABILITY * 10 ) + +#include +#include + +#if !defined(CUDA_VERSION) +#error "#include did not define CUDA_VERSION." +#endif + +#if (CUDA_VERSION < 7000) +// CUDA supports C++11 in device code starting with version 7.0. +// This includes auto type and device code internal lambdas. +#error "Cuda version 7.0 or greater required." +#endif + +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ < 300) +// Compiling with CUDA compiler for device code. +#error "Cuda device capability >= 3.0 is required." +#endif + +#ifdef KOKKOS_ENABLE_CUDA_LAMBDA +#if (CUDA_VERSION < 7050) +// CUDA supports C++11 lambdas generated in host code to be given +// to the device starting with version 7.5. But the release candidate (7.5.6) +// still identifies as 7.0. +#error "Cuda version 7.5 or greater required for host-to-device Lambda support." +#endif + +#if (CUDA_VERSION < 8000) && defined(__NVCC__) +#define KOKKOS_LAMBDA [=] __device__ +#if defined(KOKKOS_INTERNAL_ENABLE_NON_CUDA_BACKEND) +#undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA +#endif +#else +#define KOKKOS_LAMBDA [=] __host__ __device__ + +#if defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20) +#define KOKKOS_CLASS_LAMBDA [ =, *this ] __host__ __device__ +#endif +#endif + +#if defined(__NVCC__) +#define KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER +#endif +#else // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) +#undef KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA +#endif // !defined(KOKKOS_ENABLE_CUDA_LAMBDA) +#if (9000 <= CUDA_VERSION) && (CUDA_VERSION < 10000) +// CUDA 9 introduced an incorrect warning, +// see https://github.com/kokkos/kokkos/issues/1470 +#define KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND +#endif + +#if (10000 > CUDA_VERSION) +#define KOKKOS_ENABLE_PRE_CUDA_10_DEPRECATION_API +#endif + +#if defined(__CUDA_ARCH__) && (__CUDA_ARCH__ >= 700) +// PTX atomics with memory order semantics are only available on volta and later +#if !defined(KOKKOS_DISABLE_CUDA_ASM) +#if !defined(KOKKOS_ENABLE_CUDA_ASM) +#define KOKKOS_ENABLE_CUDA_ASM +#if !defined(KOKKOS_DISABLE_CUDA_ASM_ATOMICS) +#define KOKKOS_ENABLE_CUDA_ASM_ATOMICS +#endif +#endif +#endif +#endif + +#endif // #if defined( KOKKOS_ENABLE_CUDA ) && defined( __CUDACC__ ) //---------------------------------------------------------------------------- // Mapping compiler built-ins to KOKKOS_COMPILER_*** macros -#if defined( __NVCC__ ) - // NVIDIA compiler is being used. - // Code is parsed and separated into host and device code. - // Host code is compiled again with another compiler. - // Device code is compile to 'ptx'. - #define KOKKOS_COMPILER_NVCC __NVCC__ -#endif // #if defined( __NVCC__ ) +#if defined(__NVCC__) +// NVIDIA compiler is being used. +// Code is parsed and separated into host and device code. +// Host code is compiled again with another compiler. +// Device code is compile to 'ptx'. +#define KOKKOS_COMPILER_NVCC __NVCC__ +#endif // #if defined( __NVCC__ ) -#if !defined( KOKKOS_LAMBDA ) - #define KOKKOS_LAMBDA [=] +#if !defined(KOKKOS_LAMBDA) +#define KOKKOS_LAMBDA [=] #endif -#if (defined( KOKKOS_ENABLE_CXX17 ) || defined( KOKKOS_ENABLE_CXX20) )&& !defined( KOKKOS_CLASS_LAMBDA ) - #define KOKKOS_CLASS_LAMBDA [=,*this] +#if (defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20)) && \ + !defined(KOKKOS_CLASS_LAMBDA) +#define KOKKOS_CLASS_LAMBDA [ =, *this ] #endif //#if !defined( __CUDA_ARCH__ ) // Not compiling Cuda code to 'ptx'. // Intel compiler for host code. -#if defined( __INTEL_COMPILER ) - #define KOKKOS_COMPILER_INTEL __INTEL_COMPILER -#elif defined( __ICC ) - // Old define - #define KOKKOS_COMPILER_INTEL __ICC -#elif defined( __ECC ) - // Very old define - #define KOKKOS_COMPILER_INTEL __ECC +#if defined(__INTEL_COMPILER) +#define KOKKOS_COMPILER_INTEL __INTEL_COMPILER +#elif defined(__ICC) +// Old define +#define KOKKOS_COMPILER_INTEL __ICC +#elif defined(__ECC) +// Very old define +#define KOKKOS_COMPILER_INTEL __ECC #endif // CRAY compiler for host code -#if defined( _CRAYC ) - #define KOKKOS_COMPILER_CRAYC _CRAYC +#if defined(_CRAYC) +#define KOKKOS_COMPILER_CRAYC _CRAYC #endif -#if defined( __IBMCPP__ ) - // IBM C++ - #define KOKKOS_COMPILER_IBM __IBMCPP__ -#elif defined( __IBMC__ ) - #define KOKKOS_COMPILER_IBM __IBMC__ +#if defined(__IBMCPP__) +// IBM C++ +#define KOKKOS_COMPILER_IBM __IBMCPP__ +#elif defined(__IBMC__) +#define KOKKOS_COMPILER_IBM __IBMC__ #endif -#if defined( __APPLE_CC__ ) - #define KOKKOS_COMPILER_APPLECC __APPLE_CC__ +#if defined(__APPLE_CC__) +#define KOKKOS_COMPILER_APPLECC __APPLE_CC__ #endif -#if defined( __clang__ ) && !defined( KOKKOS_COMPILER_INTEL ) - #define KOKKOS_COMPILER_CLANG __clang_major__*100+__clang_minor__*10+__clang_patchlevel__ +#if defined(__clang__) && !defined(KOKKOS_COMPILER_INTEL) +#define KOKKOS_COMPILER_CLANG \ + __clang_major__ * 100 + __clang_minor__ * 10 + __clang_patchlevel__ #endif -#if !defined( __clang__ ) && !defined( KOKKOS_COMPILER_INTEL ) &&defined( __GNUC__ ) - #define KOKKOS_COMPILER_GNU __GNUC__*100+__GNUC_MINOR__*10+__GNUC_PATCHLEVEL__ +#if !defined(__clang__) && !defined(KOKKOS_COMPILER_INTEL) && defined(__GNUC__) +#define KOKKOS_COMPILER_GNU \ + __GNUC__ * 100 + __GNUC_MINOR__ * 10 + __GNUC_PATCHLEVEL__ - #if ( 472 > KOKKOS_COMPILER_GNU ) - #error "Compiling with GCC version earlier than 4.7.2 is not supported." - #endif +#if (472 > KOKKOS_COMPILER_GNU) +#error "Compiling with GCC version earlier than 4.7.2 is not supported." +#endif #endif -#if defined( __PGIC__ ) - #define KOKKOS_COMPILER_PGI __PGIC__*100+__PGIC_MINOR__*10+__PGIC_PATCHLEVEL__ +#if defined(__PGIC__) +#define KOKKOS_COMPILER_PGI \ + __PGIC__ * 100 + __PGIC_MINOR__ * 10 + __PGIC_PATCHLEVEL__ - #if ( 1540 > KOKKOS_COMPILER_PGI ) - #error "Compiling with PGI version earlier than 15.4 is not supported." - #endif +#if (1540 > KOKKOS_COMPILER_PGI) +#error "Compiling with PGI version earlier than 15.4 is not supported." +#endif #endif //#endif // #if !defined( __CUDA_ARCH__ ) //---------------------------------------------------------------------------- // Language info: C++, CUDA, OPENMP -#if defined( KOKKOS_ENABLE_CUDA ) - // Compiling Cuda code to 'ptx' +#if defined(KOKKOS_ENABLE_CUDA) +// Compiling Cuda code to 'ptx' - #define KOKKOS_FORCEINLINE_FUNCTION __device__ __host__ __forceinline__ - #define KOKKOS_INLINE_FUNCTION __device__ __host__ inline - #define KOKKOS_FUNCTION __device__ __host__ - #if defined( KOKKOS_COMPILER_NVCC ) - #define KOKKOS_INLINE_FUNCTION_DELETED inline - #else - #define KOKKOS_INLINE_FUNCTION_DELETED __device__ __host__ inline - #endif -#endif // #if defined( __CUDA_ARCH__ ) +#define KOKKOS_FORCEINLINE_FUNCTION __device__ __host__ __forceinline__ +#define KOKKOS_IMPL_FORCEINLINE __forceinline__ +#define KOKKOS_INLINE_FUNCTION __device__ __host__ inline +#define KOKKOS_FUNCTION __device__ __host__ +#if defined(KOKKOS_COMPILER_NVCC) +#define KOKKOS_INLINE_FUNCTION_DELETED inline +#else +#define KOKKOS_INLINE_FUNCTION_DELETED __device__ __host__ inline +#endif +#endif // #if defined( __CUDA_ARCH__ ) -#if defined( KOKKOS_ENABLE_ROCM ) && defined( __HCC__ ) +#if defined(KOKKOS_ENABLE_ROCM) && defined(__HCC__) - #define KOKKOS_FORCEINLINE_FUNCTION __attribute__((amp,cpu)) inline - #define KOKKOS_INLINE_FUNCTION __attribute__((amp,cpu)) inline - #define KOKKOS_FUNCTION __attribute__((amp,cpu)) - #define KOKKOS_LAMBDA [=] __attribute__((amp,cpu)) +#define KOKKOS_FORCEINLINE_FUNCTION __attribute__((amp, cpu)) inline +#define KOKKOS_INLINE_FUNCTION __attribute__((amp, cpu)) inline +#define KOKKOS_FUNCTION __attribute__((amp, cpu)) +#define KOKKOS_LAMBDA [=] __attribute__((amp, cpu)) #endif -#if defined( _OPENMP ) - // Compiling with OpenMP. - // The value of _OPENMP is an integer value YYYYMM - // where YYYY and MM are the year and month designation - // of the supported OpenMP API version. -#endif // #if defined( _OPENMP ) +#if defined(_OPENMP) +// Compiling with OpenMP. +// The value of _OPENMP is an integer value YYYYMM +// where YYYY and MM are the year and month designation +// of the supported OpenMP API version. +#endif // #if defined( _OPENMP ) //---------------------------------------------------------------------------- // Intel compiler macros -#if defined( KOKKOS_COMPILER_INTEL ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - #define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - #define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - #if ( 1800 > KOKKOS_COMPILER_INTEL ) - #define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #endif - - #if ( __INTEL_COMPILER > 1400 ) - #define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - #endif - - #if ! defined( KOKKOS_MEMORY_ALIGNMENT ) - #define KOKKOS_MEMORY_ALIGNMENT 64 - #endif - - #define KOKKOS_RESTRICT __restrict__ - - #ifndef KOKKOS_IMPL_ALIGN_PTR - #define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((align_value(size))) - #endif - - #if ( 1400 > KOKKOS_COMPILER_INTEL ) - #if ( 1300 > KOKKOS_COMPILER_INTEL ) - #error "Compiling with Intel version earlier than 13.0 is not supported. Official minimal version is 14.0." - #else - #warning "Compiling with Intel version 13.x probably works but is not officially supported. Official minimal version is 14.0." - #endif - #endif - - #if !defined( KOKKOS_ENABLE_ASM ) && !defined( _WIN32 ) - #define KOKKOS_ENABLE_ASM 1 - #endif - - #if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - #if !defined( _WIN32 ) - #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) - #else - #define KOKKOS_FORCEINLINE_FUNCTION inline - #endif - #endif - - #if defined( KOKKOS_ARCH_AVX512MIC ) - #define KOKKOS_ENABLE_RFO_PREFETCH 1 - #if (KOKKOS_COMPILER_INTEL < 1800) && !defined(KOKKOS_KNL_USE_ASM_WORKAROUND) - #define KOKKOS_KNL_USE_ASM_WORKAROUND 1 - #endif - #endif - - #if defined( __MIC__ ) - // Compiling for Xeon Phi - #endif +#if defined(KOKKOS_COMPILER_INTEL) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +#if (1800 > KOKKOS_COMPILER_INTEL) +#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#endif + +#if (__INTEL_COMPILER > 1400) +#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +#endif + +#if !defined(KOKKOS_MEMORY_ALIGNMENT) +#define KOKKOS_MEMORY_ALIGNMENT 64 +#endif + +#define KOKKOS_RESTRICT __restrict__ + +#ifndef KOKKOS_IMPL_ALIGN_PTR +#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((align_value(size))) +#endif + +#if (1400 > KOKKOS_COMPILER_INTEL) +#if (1300 > KOKKOS_COMPILER_INTEL) +#error \ + "Compiling with Intel version earlier than 13.0 is not supported. Official minimal version is 14.0." +#else +#warning \ + "Compiling with Intel version 13.x probably works but is not officially supported. Official minimal version is 14.0." +#endif +#endif + +#if !defined(KOKKOS_ENABLE_ASM) && !defined(_WIN32) +#define KOKKOS_ENABLE_ASM 1 +#endif + +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#if !defined(_WIN32) +#define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) +#define KOKKOS_IMPL_FORCEINLINE __attribute__((always_inline)) +#else +#define KOKKOS_FORCEINLINE_FUNCTION inline +#endif +#endif + +#if defined(KOKKOS_ARCH_AVX512MIC) +#define KOKKOS_ENABLE_RFO_PREFETCH 1 +#if (KOKKOS_COMPILER_INTEL < 1800) && !defined(KOKKOS_KNL_USE_ASM_WORKAROUND) +#define KOKKOS_KNL_USE_ASM_WORKAROUND 1 +#endif +#endif + +#if defined(__MIC__) +// Compiling for Xeon Phi +#endif #endif //---------------------------------------------------------------------------- // Cray compiler macros -#if defined( KOKKOS_COMPILER_CRAYC ) +#if defined(KOKKOS_COMPILER_CRAYC) #endif //---------------------------------------------------------------------------- // IBM Compiler macros -#if defined( KOKKOS_COMPILER_IBM ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - //#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - //#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_IBM) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +//#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +//#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #if ! defined( KOKKOS_ENABLE_ASM ) - #define KOKKOS_ENABLE_ASM 1 - #endif +#if !defined(KOKKOS_ENABLE_ASM) +#define KOKKOS_ENABLE_ASM 1 +#endif #endif //---------------------------------------------------------------------------- // CLANG compiler macros -#if defined( KOKKOS_COMPILER_CLANG ) - //#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - //#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - //#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_CLANG) +//#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +//#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +//#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) - #endif +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) +#define KOKKOS_IMPL_FORCEINLINE __attribute__((always_inline)) +#endif - #if !defined( KOKKOS_IMPL_ALIGN_PTR ) - #define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((aligned(size))) - #endif +#if !defined(KOKKOS_IMPL_ALIGN_PTR) +#define KOKKOS_IMPL_ALIGN_PTR(size) __attribute__((aligned(size))) +#endif #endif //---------------------------------------------------------------------------- // GNU Compiler macros -#if defined( KOKKOS_COMPILER_GNU ) - //#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - //#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - //#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_GNU) +//#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +//#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +//#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 - #if defined( KOKKOS_ARCH_AVX512MIC ) - #define KOKKOS_ENABLE_RFO_PREFETCH 1 - #endif +#if defined(KOKKOS_ARCH_AVX512MIC) +#define KOKKOS_ENABLE_RFO_PREFETCH 1 +#endif - #if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - #define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) - #endif +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#define KOKKOS_FORCEINLINE_FUNCTION inline __attribute__((always_inline)) +#define KOKKOS_IMPL_FORCEINLINE __attribute__((always_inline)) +#endif - #define KOKKOS_RESTRICT __restrict__ +#define KOKKOS_RESTRICT __restrict__ - #if !defined( KOKKOS_ENABLE_ASM ) && !defined( __PGIC__ ) && \ - ( defined( __amd64 ) || defined( __amd64__ ) || \ - defined( __x86_64 ) || defined( __x86_64__ ) || \ - defined(__PPC64__) ) - #define KOKKOS_ENABLE_ASM 1 - #endif +#if !defined(KOKKOS_ENABLE_ASM) && !defined(__PGIC__) && \ + (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || \ + defined(__x86_64__) || defined(__PPC64__)) +#define KOKKOS_ENABLE_ASM 1 +#endif #endif //---------------------------------------------------------------------------- -#if defined( KOKKOS_COMPILER_PGI ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - #define KOKKOS_ENABLE_PRAGMA_IVDEP 1 - //#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 - #define KOKKOS_ENABLE_PRAGMA_VECTOR 1 - //#define KOKKOS_ENABLE_PRAGMA_SIMD 1 +#if defined(KOKKOS_COMPILER_PGI) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +#define KOKKOS_ENABLE_PRAGMA_IVDEP 1 +//#define KOKKOS_ENABLE_PRAGMA_LOOPCOUNT 1 +#define KOKKOS_ENABLE_PRAGMA_VECTOR 1 +//#define KOKKOS_ENABLE_PRAGMA_SIMD 1 #endif //---------------------------------------------------------------------------- -#if defined( KOKKOS_COMPILER_NVCC ) - #if defined( __CUDA_ARCH__ ) - #define KOKKOS_ENABLE_PRAGMA_UNROLL 1 - #endif +#if defined(KOKKOS_COMPILER_NVCC) +#if defined(__CUDA_ARCH__) +#define KOKKOS_ENABLE_PRAGMA_UNROLL 1 +#endif #endif //---------------------------------------------------------------------------- // Define function marking macros if compiler specific macros are undefined: -#if !defined( KOKKOS_FORCEINLINE_FUNCTION ) - define KOKKOS_FORCEINLINE_FUNCTION inline +#if !defined(KOKKOS_FORCEINLINE_FUNCTION) +#define KOKKOS_FORCEINLINE_FUNCTION inline #endif -#if !defined( KOKKOS_INLINE_FUNCTION ) - #define KOKKOS_INLINE_FUNCTION inline +#if !defined(KOKKOS_IMPL_FORCEINLINE) +#define KOKKOS_IMPL_FORCEINLINE inline #endif -#if !defined( KOKKOS_FUNCTION ) - #define KOKKOS_FUNCTION /**/ +#if !defined(KOKKOS_INLINE_FUNCTION) +#define KOKKOS_INLINE_FUNCTION inline #endif -#if !defined( KOKKOS_INLINE_FUNCTION_DELETED ) - #define KOKKOS_INLINE_FUNCTION_DELETED inline +#if !defined(KOKKOS_FUNCTION) +#define KOKKOS_FUNCTION /**/ +#endif + +#if !defined(KOKKOS_INLINE_FUNCTION_DELETED) +#define KOKKOS_INLINE_FUNCTION_DELETED inline #endif //---------------------------------------------------------------------------- // Define empty macro for restrict if necessary: -#if !defined( KOKKOS_RESTRICT ) - #define KOKKOS_RESTRICT +#if !defined(KOKKOS_RESTRICT) +#define KOKKOS_RESTRICT #endif //---------------------------------------------------------------------------- // Define Macro for alignment: -#if ! defined( KOKKOS_MEMORY_ALIGNMENT ) - #define KOKKOS_MEMORY_ALIGNMENT 64 +#if !defined(KOKKOS_MEMORY_ALIGNMENT) +#define KOKKOS_MEMORY_ALIGNMENT 64 #endif -#if ! defined( KOKKOS_MEMORY_ALIGNMENT_THRESHOLD ) - #define KOKKOS_MEMORY_ALIGNMENT_THRESHOLD 1 +#if !defined(KOKKOS_MEMORY_ALIGNMENT_THRESHOLD) +#define KOKKOS_MEMORY_ALIGNMENT_THRESHOLD 1 #endif -#if !defined( KOKKOS_IMPL_ALIGN_PTR ) - #define KOKKOS_IMPL_ALIGN_PTR(size) /* */ +#if !defined(KOKKOS_IMPL_ALIGN_PTR) +#define KOKKOS_IMPL_ALIGN_PTR(size) /* */ #endif //---------------------------------------------------------------------------- // Determine the default execution space for parallel dispatch. // There is zero or one default execution space specified. -#if 1 < ( ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) ? 1 : 0 ) + \ - ( defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) ? 1 : 0 ) ) - #error "More than one KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_* specified." +#if 1 < ((defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) ? 1 : 0) + \ + (defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) ? 1 : 0)) +#error "More than one KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_* specified." #endif // If default is not specified then chose from enabled execution spaces. // Priority: CUDA, OPENMP, THREADS, QTHREADS, HPX, SERIAL -#if defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS ) +#if defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS) //#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX ) -#elif defined( KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL ) -#elif defined( KOKKOS_ENABLE_CUDA ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA -#elif defined( KOKKOS_ENABLE_ROCM ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM -#elif defined( KOKKOS_ENABLE_OPENMPTARGET ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET -#elif defined( KOKKOS_ENABLE_OPENMP ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP -#elif defined( KOKKOS_ENABLE_THREADS ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX) +#elif defined(KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL) +#elif defined(KOKKOS_ENABLE_CUDA) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_CUDA +#elif defined(KOKKOS_ENABLE_ROCM) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_ROCM +#elif defined(KOKKOS_ENABLE_OPENMPTARGET) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMPTARGET +#elif defined(KOKKOS_ENABLE_OPENMP) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_OPENMP +#elif defined(KOKKOS_ENABLE_THREADS) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_THREADS //#elif defined( KOKKOS_ENABLE_QTHREADS ) // #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_QTHREADS -#elif defined( KOKKOS_ENABLE_HPX ) - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX +#elif defined(KOKKOS_ENABLE_HPX) +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_HPX #else - #define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL +#define KOKKOS_ENABLE_DEFAULT_DEVICE_TYPE_SERIAL #endif //---------------------------------------------------------------------------- // Determine for what space the code is being compiled: -#if defined( __CUDACC__ ) && defined( __CUDA_ARCH__ ) && defined( KOKKOS_ENABLE_CUDA ) - #define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA -#elif defined( __HCC__ ) && defined( __HCC_ACCELERATOR__ ) && defined( KOKKOS_ENABLE_ROCM ) - #define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU +#if defined(__CUDACC__) && defined(__CUDA_ARCH__) && defined(KOKKOS_ENABLE_CUDA) +#define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA +#elif defined(__HCC__) && defined(__HCC_ACCELERATOR__) && \ + defined(KOKKOS_ENABLE_ROCM) +#define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_ROCM_GPU #else - #define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST +#define KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST #endif //---------------------------------------------------------------------------- -#if ( defined( _POSIX_C_SOURCE ) && _POSIX_C_SOURCE >= 200112L ) || \ - ( defined( _XOPEN_SOURCE ) && _XOPEN_SOURCE >= 600 ) - #if defined( KOKKOS_ENABLE_PERFORMANCE_POSIX_MEMALIGN ) - #define KOKKOS_ENABLE_POSIX_MEMALIGN 1 - #endif +#if (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L) || \ + (defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 600) +#if defined(KOKKOS_ENABLE_PERFORMANCE_POSIX_MEMALIGN) +#define KOKKOS_ENABLE_POSIX_MEMALIGN 1 +#endif #endif //---------------------------------------------------------------------------- @@ -547,53 +561,65 @@ // and use relocateable device code to enable the task policy. // nvcc relocatable device code option: --relocatable-device-code=true -#if ( defined( KOKKOS_ENABLE_CUDA ) ) - #if ( 8000 <= CUDA_VERSION ) && defined( KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE ) - #define KOKKOS_ENABLE_TASKDAG - #endif +#if (defined(KOKKOS_ENABLE_CUDA)) +#if (8000 <= CUDA_VERSION) && \ + defined(KOKKOS_ENABLE_CUDA_RELOCATABLE_DEVICE_CODE) +#define KOKKOS_ENABLE_TASKDAG +#endif #else - #define KOKKOS_ENABLE_TASKDAG +#define KOKKOS_ENABLE_TASKDAG #endif - -#if defined ( KOKKOS_ENABLE_CUDA ) - #if ( 9000 <= CUDA_VERSION ) - #define KOKKOS_IMPL_CUDA_VERSION_9_WORKAROUND - #if ( __CUDA_ARCH__ ) - #define KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK - #endif - #endif +#if defined(KOKKOS_ENABLE_CUDA) +#if (9000 <= CUDA_VERSION) +#define KOKKOS_IMPL_CUDA_VERSION_9_WORKAROUND +#if (__CUDA_ARCH__) +#define KOKKOS_IMPL_CUDA_SYNCWARP_NEEDS_MASK +#endif +#endif #endif #define KOKKOS_INVALID_INDEX (~std::size_t(0)) #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - #define KOKKOS_IMPL_CTOR_DEFAULT_ARG 0 +#define KOKKOS_IMPL_CTOR_DEFAULT_ARG 0 #else - #define KOKKOS_IMPL_CTOR_DEFAULT_ARG KOKKOS_INVALID_INDEX +#define KOKKOS_IMPL_CTOR_DEFAULT_ARG KOKKOS_INVALID_INDEX #endif -#if (defined(KOKKOS_ENABLE_CXX14) || defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20)) - #define KOKKOS_CONSTEXPR_14 constexpr - #define KOKKOS_DEPRECATED [[deprecated]] - #define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE +#if (defined(KOKKOS_ENABLE_CXX14) || defined(KOKKOS_ENABLE_CXX17) || \ + defined(KOKKOS_ENABLE_CXX20)) +#define KOKKOS_CONSTEXPR_14 constexpr +#define KOKKOS_DEPRECATED [[deprecated]] +#define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE +#else +#define KOKKOS_CONSTEXPR_14 +#if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) +#define KOKKOS_DEPRECATED +#define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE __attribute__((deprecated)) #else - #define KOKKOS_CONSTEXPR_14 - #if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) - #define KOKKOS_DEPRECATED - #define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE __attribute__ ((deprecated)) - #else - #define KOKKOS_DEPRECATED - #define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE - #endif +#define KOKKOS_DEPRECATED +#define KOKKOS_DEPRECATED_TRAILING_ATTRIBUTE +#endif #endif - // DJS 05/28/2019: Bugfix: Issue 2155 -// Use KOKKOS_ENABLE_CUDA_LDG_INTRINSIC to avoid memory leak in RandomAccess View +// Use KOKKOS_ENABLE_CUDA_LDG_INTRINSIC to avoid memory leak in RandomAccess +// View #if defined(KOKKOS_ENABLE_CUDA) && !defined(KOKKOS_ENABLE_CUDA_LDG_INTRINSIC) - #define KOKKOS_ENABLE_CUDA_LDG_INTRINSIC +#define KOKKOS_ENABLE_CUDA_LDG_INTRINSIC #endif -#endif // #ifndef KOKKOS_MACROS_HPP +#if defined(KOKKOS_ENABLE_CXX17) || defined(KOKKOS_ENABLE_CXX20) +#define KOKKOS_ATTRIBUTE_NODISCARD [[nodiscard]] +#else +#define KOKKOS_ATTRIBUTE_NODISCARD +#endif + +#if defined(KOKKOS_COMPILER_GNU) || defined(KOKKOS_COMPILER_CLANG) || \ + defined(KOKKOS_COMPILER_INTEL) || defined(KOKKOS_COMPILER_PGI) +#define KOKKOS_IMPL_ENABLE_STACKTRACE +#define KOKKOS_IMPL_ENABLE_CXXABI +#endif +#endif // #ifndef KOKKOS_MACROS_HPP diff --git a/lib/kokkos/core/src/Kokkos_MasterLock.hpp b/lib/kokkos/core/src/Kokkos_MasterLock.hpp index 2db22d2fdd..3c45e131a0 100644 --- a/lib/kokkos/core/src/Kokkos_MasterLock.hpp +++ b/lib/kokkos/core/src/Kokkos_MasterLock.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,7 +47,8 @@ #include -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { // my be used to coordinate work between master instances // SHOULD NOT be used within a parallel algorithm @@ -67,7 +69,7 @@ namespace Kokkos { namespace Experimental { template class MasterLock; -}} // namespace Kokkos::Experimental - -#endif //KOKKOS_MASTER_LOCK_HPP +} // namespace Experimental +} // namespace Kokkos +#endif // KOKKOS_MASTER_LOCK_HPP diff --git a/lib/kokkos/core/src/Kokkos_MemoryPool.hpp b/lib/kokkos/core/src/Kokkos_MemoryPool.hpp index 365db2baec..5228f36612 100644 --- a/lib/kokkos/core/src/Kokkos_MemoryPool.hpp +++ b/lib/kokkos/core/src/Kokkos_MemoryPool.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -55,37 +56,34 @@ namespace Kokkos { namespace Impl { /* Report violation of size constraints: * min_block_alloc_size <= max_block_alloc_size - * max_block_alloc_size <= min_superblock_size + * max_block_alloc_size <= min_superblock_size * min_superblock_size <= max_superblock_size * min_superblock_size <= min_total_alloc_size - * min_superblock_size <= min_block_alloc_size * + * min_superblock_size <= min_block_alloc_size * * max_block_per_superblock */ -void memory_pool_bounds_verification - ( size_t min_block_alloc_size - , size_t max_block_alloc_size - , size_t min_superblock_size - , size_t max_superblock_size - , size_t max_block_per_superblock - , size_t min_total_alloc_size - ); -} -} +void memory_pool_bounds_verification(size_t min_block_alloc_size, + size_t max_block_alloc_size, + size_t min_superblock_size, + size_t max_superblock_size, + size_t max_block_per_superblock, + size_t min_total_alloc_size); +} // namespace Impl +} // namespace Kokkos namespace Kokkos { -template< typename DeviceType > +template class MemoryPool { -private: + private: + typedef typename Kokkos::Impl::concurrent_bitset CB; - typedef typename Kokkos::Impl::concurrent_bitset CB ; - - enum : uint32_t { bits_per_int_lg2 = CB::bits_per_int_lg2 }; - enum : uint32_t { state_shift = CB::state_shift }; - enum : uint32_t { state_used_mask = CB::state_used_mask }; + enum : uint32_t { bits_per_int_lg2 = CB::bits_per_int_lg2 }; + enum : uint32_t { state_shift = CB::state_shift }; + enum : uint32_t { state_used_mask = CB::state_used_mask }; enum : uint32_t { state_header_mask = CB::state_header_mask }; enum : uint32_t { max_bit_count_lg2 = CB::max_bit_count_lg2 }; - enum : uint32_t { max_bit_count = CB::max_bit_count }; + enum : uint32_t { max_bit_count = CB::max_bit_count }; enum : uint32_t { HINT_PER_BLOCK_SIZE = 2 }; @@ -109,231 +107,219 @@ private: * Thus A_block_size < B_block_size <=> A_block_state > B_block_state */ - typedef typename DeviceType::memory_space base_memory_space ; - - enum { accessible = - Kokkos::Impl::MemorySpaceAccess< Kokkos::HostSpace - , base_memory_space >::accessible }; - - typedef Kokkos::Impl::SharedAllocationTracker Tracker ; - typedef Kokkos::Impl::SharedAllocationRecord - < base_memory_space > Record ; + typedef typename DeviceType::memory_space base_memory_space; - Tracker m_tracker ; - uint32_t * m_sb_state_array ; - uint32_t m_sb_state_size ; - uint32_t m_sb_size_lg2 ; - uint32_t m_max_block_size_lg2 ; - uint32_t m_min_block_size_lg2 ; - int32_t m_sb_count ; - int32_t m_hint_offset ; // Offset to K * #block_size array of hints - int32_t m_data_offset ; // Offset to 0th superblock data - int32_t m_unused_padding ; - -public: + enum { + accessible = Kokkos::Impl::MemorySpaceAccess::accessible + }; + typedef Kokkos::Impl::SharedAllocationTracker Tracker; + typedef Kokkos::Impl::SharedAllocationRecord Record; + + Tracker m_tracker; + uint32_t *m_sb_state_array; + uint32_t m_sb_state_size; + uint32_t m_sb_size_lg2; + uint32_t m_max_block_size_lg2; + uint32_t m_min_block_size_lg2; + int32_t m_sb_count; + int32_t m_hint_offset; // Offset to K * #block_size array of hints + int32_t m_data_offset; // Offset to 0th superblock data + int32_t m_unused_padding; + + public: using memory_space = typename DeviceType::memory_space; /**\brief The maximum size of a superblock and block */ - enum : uint32_t { max_superblock_size = 1LU << 31 /* 2 gigabytes */ }; + enum : uint32_t { max_superblock_size = 1LU << 31 /* 2 gigabytes */ }; enum : uint32_t { max_block_per_superblock = max_bit_count }; //-------------------------------------------------------------------------- KOKKOS_INLINE_FUNCTION - bool operator==(MemoryPool const& other) const - { return m_sb_state_array == other.m_sb_state_array; } + bool operator==(MemoryPool const &other) const { + return m_sb_state_array == other.m_sb_state_array; + } KOKKOS_INLINE_FUNCTION - size_t capacity() const noexcept - { return size_t(m_sb_count) << m_sb_size_lg2 ; } + size_t capacity() const noexcept { + return size_t(m_sb_count) << m_sb_size_lg2; + } KOKKOS_INLINE_FUNCTION - size_t min_block_size() const noexcept - { return ( 1LU << m_min_block_size_lg2 ); } + size_t min_block_size() const noexcept { + return (1LU << m_min_block_size_lg2); + } KOKKOS_INLINE_FUNCTION - size_t max_block_size() const noexcept - { return ( 1LU << m_max_block_size_lg2 ); } + size_t max_block_size() const noexcept { + return (1LU << m_max_block_size_lg2); + } struct usage_statistics { - size_t capacity_bytes ; ///< Capacity in bytes - size_t superblock_bytes ; ///< Superblock size in bytes - size_t max_block_bytes ; ///< Maximum block size in bytes - size_t min_block_bytes ; ///< Minimum block size in bytes - size_t capacity_superblocks ; ///< Number of superblocks - size_t consumed_superblocks ; ///< Superblocks assigned to allocations - size_t consumed_blocks ; ///< Number of allocations - size_t consumed_bytes ; ///< Bytes allocated - size_t reserved_blocks ; ///< Unallocated blocks in assigned superblocks - size_t reserved_bytes ; ///< Unallocated bytes in assigned superblocks + size_t capacity_bytes; ///< Capacity in bytes + size_t superblock_bytes; ///< Superblock size in bytes + size_t max_block_bytes; ///< Maximum block size in bytes + size_t min_block_bytes; ///< Minimum block size in bytes + size_t capacity_superblocks; ///< Number of superblocks + size_t consumed_superblocks; ///< Superblocks assigned to allocations + size_t consumed_blocks; ///< Number of allocations + size_t consumed_bytes; ///< Bytes allocated + size_t reserved_blocks; ///< Unallocated blocks in assigned superblocks + size_t reserved_bytes; ///< Unallocated bytes in assigned superblocks }; - void get_usage_statistics( usage_statistics & stats ) const - { - Kokkos::HostSpace host ; + void get_usage_statistics(usage_statistics &stats) const { + Kokkos::HostSpace host; - const size_t alloc_size = m_hint_offset * sizeof(uint32_t); + const size_t alloc_size = m_hint_offset * sizeof(uint32_t); - uint32_t * const sb_state_array = - accessible ? m_sb_state_array : (uint32_t *) host.allocate(alloc_size); + uint32_t *const sb_state_array = + accessible ? m_sb_state_array : (uint32_t *)host.allocate(alloc_size); - if ( ! accessible ) { - Kokkos::Impl::DeepCopy< Kokkos::HostSpace , base_memory_space > - ( sb_state_array , m_sb_state_array , alloc_size ); - } - - stats.superblock_bytes = ( 1LU << m_sb_size_lg2 ); - stats.max_block_bytes = ( 1LU << m_max_block_size_lg2 ); - stats.min_block_bytes = ( 1LU << m_min_block_size_lg2 ); - stats.capacity_bytes = stats.superblock_bytes * m_sb_count ; - stats.capacity_superblocks = m_sb_count ; - stats.consumed_superblocks = 0 ; - stats.consumed_blocks = 0 ; - stats.consumed_bytes = 0 ; - stats.reserved_blocks = 0 ; - stats.reserved_bytes = 0 ; - - const uint32_t * sb_state_ptr = sb_state_array ; - - for ( int32_t i = 0 ; i < m_sb_count - ; ++i , sb_state_ptr += m_sb_state_size ) { - - const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift ; - - if ( block_count_lg2 ) { - const uint32_t block_count = 1u << block_count_lg2 ; - const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2 ; - const uint32_t block_size = 1u << block_size_lg2 ; - const uint32_t block_used = (*sb_state_ptr) & state_used_mask ; - - stats.consumed_superblocks++ ; - stats.consumed_blocks += block_used ; - stats.consumed_bytes += block_used * block_size ; - stats.reserved_blocks += block_count - block_used ; - stats.reserved_bytes += (block_count - block_used ) * block_size ; - } - } + if (!accessible) { + Kokkos::Impl::DeepCopy( + sb_state_array, m_sb_state_array, alloc_size); + } - if ( ! accessible ) { - host.deallocate( sb_state_array, alloc_size ); + stats.superblock_bytes = (1LU << m_sb_size_lg2); + stats.max_block_bytes = (1LU << m_max_block_size_lg2); + stats.min_block_bytes = (1LU << m_min_block_size_lg2); + stats.capacity_bytes = stats.superblock_bytes * m_sb_count; + stats.capacity_superblocks = m_sb_count; + stats.consumed_superblocks = 0; + stats.consumed_blocks = 0; + stats.consumed_bytes = 0; + stats.reserved_blocks = 0; + stats.reserved_bytes = 0; + + const uint32_t *sb_state_ptr = sb_state_array; + + for (int32_t i = 0; i < m_sb_count; ++i, sb_state_ptr += m_sb_state_size) { + const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift; + + if (block_count_lg2) { + const uint32_t block_count = 1u << block_count_lg2; + const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2; + const uint32_t block_size = 1u << block_size_lg2; + const uint32_t block_used = (*sb_state_ptr) & state_used_mask; + + stats.consumed_superblocks++; + stats.consumed_blocks += block_used; + stats.consumed_bytes += block_used * block_size; + stats.reserved_blocks += block_count - block_used; + stats.reserved_bytes += (block_count - block_used) * block_size; } } - void print_state( std::ostream & s ) const - { - Kokkos::HostSpace host ; - - const size_t alloc_size = m_hint_offset * sizeof(uint32_t); + if (!accessible) { + host.deallocate(sb_state_array, alloc_size); + } + } - uint32_t * const sb_state_array = - accessible ? m_sb_state_array : (uint32_t *) host.allocate(alloc_size); + void print_state(std::ostream &s) const { + Kokkos::HostSpace host; - if ( ! accessible ) { - Kokkos::Impl::DeepCopy< Kokkos::HostSpace , base_memory_space > - ( sb_state_array , m_sb_state_array , alloc_size ); - } + const size_t alloc_size = m_hint_offset * sizeof(uint32_t); - const uint32_t * sb_state_ptr = sb_state_array ; + uint32_t *const sb_state_array = + accessible ? m_sb_state_array : (uint32_t *)host.allocate(alloc_size); - s << "pool_size(" << ( size_t(m_sb_count) << m_sb_size_lg2 ) << ")" - << " superblock_size(" << ( 1LU << m_sb_size_lg2 ) << ")" << std::endl ; + if (!accessible) { + Kokkos::Impl::DeepCopy( + sb_state_array, m_sb_state_array, alloc_size); + } - for ( int32_t i = 0 ; i < m_sb_count - ; ++i , sb_state_ptr += m_sb_state_size ) { + const uint32_t *sb_state_ptr = sb_state_array; - if ( *sb_state_ptr ) { + s << "pool_size(" << (size_t(m_sb_count) << m_sb_size_lg2) << ")" + << " superblock_size(" << (1LU << m_sb_size_lg2) << ")" << std::endl; - const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift ; - const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2 ; - const uint32_t block_count = 1u << block_count_lg2 ; - const uint32_t block_used = (*sb_state_ptr) & state_used_mask ; + for (int32_t i = 0; i < m_sb_count; ++i, sb_state_ptr += m_sb_state_size) { + if (*sb_state_ptr) { + const uint32_t block_count_lg2 = (*sb_state_ptr) >> state_shift; + const uint32_t block_size_lg2 = m_sb_size_lg2 - block_count_lg2; + const uint32_t block_count = 1u << block_count_lg2; + const uint32_t block_used = (*sb_state_ptr) & state_used_mask; - s << "Superblock[ " << i << " / " << m_sb_count << " ] {" - << " block_size(" << ( 1 << block_size_lg2 ) << ")" - << " block_count( " << block_used - << " / " << block_count << " )" - << std::endl ; - } + s << "Superblock[ " << i << " / " << m_sb_count << " ] {" + << " block_size(" << (1 << block_size_lg2) << ")" + << " block_count( " << block_used << " / " << block_count << " )" + << std::endl; } + } - if ( ! accessible ) { - host.deallocate( sb_state_array, alloc_size ); - } + if (!accessible) { + host.deallocate(sb_state_array, alloc_size); } + } //-------------------------------------------------------------------------- #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - KOKKOS_INLINE_FUNCTION MemoryPool( MemoryPool && rhs ) - : m_tracker(std::move(rhs.m_tracker)) - , m_sb_state_array(std::move(rhs.m_sb_state_array)) - , m_sb_state_size(std::move(rhs.m_sb_state_size)) - , m_sb_size_lg2(std::move(rhs.m_sb_size_lg2)) - , m_max_block_size_lg2(std::move(rhs.m_max_block_size_lg2)) - , m_min_block_size_lg2(std::move(rhs.m_min_block_size_lg2)) - , m_sb_count(std::move(rhs.m_sb_count)) - , m_hint_offset(std::move(rhs.m_hint_offset)) - , m_data_offset(std::move(rhs.m_data_offset)) - { - } - KOKKOS_INLINE_FUNCTION MemoryPool( const MemoryPool & rhs ) - : m_tracker(rhs.m_tracker) - , m_sb_state_array(rhs.m_sb_state_array) - , m_sb_state_size(rhs.m_sb_state_size) - , m_sb_size_lg2(rhs.m_sb_size_lg2) - , m_max_block_size_lg2(rhs.m_max_block_size_lg2) - , m_min_block_size_lg2(rhs.m_min_block_size_lg2) - , m_sb_count(rhs.m_sb_count) - , m_hint_offset(rhs.m_hint_offset) - , m_data_offset(rhs.m_data_offset) - { - } - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( MemoryPool && rhs ) - { - m_tracker = std::move(rhs.m_tracker); - m_sb_state_array = std::move(rhs.m_sb_state_array); - m_sb_state_size = std::move(rhs.m_sb_state_size); - m_sb_size_lg2 = std::move(rhs.m_sb_size_lg2); + KOKKOS_INLINE_FUNCTION MemoryPool(MemoryPool &&rhs) + : m_tracker(std::move(rhs.m_tracker)), + m_sb_state_array(std::move(rhs.m_sb_state_array)), + m_sb_state_size(std::move(rhs.m_sb_state_size)), + m_sb_size_lg2(std::move(rhs.m_sb_size_lg2)), + m_max_block_size_lg2(std::move(rhs.m_max_block_size_lg2)), + m_min_block_size_lg2(std::move(rhs.m_min_block_size_lg2)), + m_sb_count(std::move(rhs.m_sb_count)), + m_hint_offset(std::move(rhs.m_hint_offset)), + m_data_offset(std::move(rhs.m_data_offset)) {} + KOKKOS_INLINE_FUNCTION MemoryPool(const MemoryPool &rhs) + : m_tracker(rhs.m_tracker), + m_sb_state_array(rhs.m_sb_state_array), + m_sb_state_size(rhs.m_sb_state_size), + m_sb_size_lg2(rhs.m_sb_size_lg2), + m_max_block_size_lg2(rhs.m_max_block_size_lg2), + m_min_block_size_lg2(rhs.m_min_block_size_lg2), + m_sb_count(rhs.m_sb_count), + m_hint_offset(rhs.m_hint_offset), + m_data_offset(rhs.m_data_offset) {} + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(MemoryPool &&rhs) { + m_tracker = std::move(rhs.m_tracker); + m_sb_state_array = std::move(rhs.m_sb_state_array); + m_sb_state_size = std::move(rhs.m_sb_state_size); + m_sb_size_lg2 = std::move(rhs.m_sb_size_lg2); m_max_block_size_lg2 = std::move(rhs.m_max_block_size_lg2); m_min_block_size_lg2 = std::move(rhs.m_min_block_size_lg2); - m_sb_count = std::move(rhs.m_sb_count); - m_hint_offset = std::move(rhs.m_hint_offset); - m_data_offset = std::move(rhs.m_data_offset); + m_sb_count = std::move(rhs.m_sb_count); + m_hint_offset = std::move(rhs.m_hint_offset); + m_data_offset = std::move(rhs.m_data_offset); return *this; } - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( const MemoryPool & rhs ) - { - m_tracker = rhs.m_tracker; - m_sb_state_array = rhs.m_sb_state_array; - m_sb_state_size = rhs.m_sb_state_size; - m_sb_size_lg2 = rhs.m_sb_size_lg2; + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(const MemoryPool &rhs) { + m_tracker = rhs.m_tracker; + m_sb_state_array = rhs.m_sb_state_array; + m_sb_state_size = rhs.m_sb_state_size; + m_sb_size_lg2 = rhs.m_sb_size_lg2; m_max_block_size_lg2 = rhs.m_max_block_size_lg2; m_min_block_size_lg2 = rhs.m_min_block_size_lg2; - m_sb_count = rhs.m_sb_count; - m_hint_offset = rhs.m_hint_offset; - m_data_offset = rhs.m_data_offset; + m_sb_count = rhs.m_sb_count; + m_hint_offset = rhs.m_hint_offset; + m_data_offset = rhs.m_data_offset; return *this; } #else - KOKKOS_INLINE_FUNCTION MemoryPool( MemoryPool && ) = default ; - KOKKOS_INLINE_FUNCTION MemoryPool( const MemoryPool & ) = default ; - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( MemoryPool && ) = default ; - KOKKOS_INLINE_FUNCTION MemoryPool & operator = ( const MemoryPool & ) = default ; + KOKKOS_INLINE_FUNCTION MemoryPool(MemoryPool &&) = default; + KOKKOS_INLINE_FUNCTION MemoryPool(const MemoryPool &) = default; + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(MemoryPool &&) = default; + KOKKOS_INLINE_FUNCTION MemoryPool &operator=(const MemoryPool &) = default; #endif KOKKOS_INLINE_FUNCTION MemoryPool() - : m_tracker() - , m_sb_state_array(0) - , m_sb_state_size(0) - , m_sb_size_lg2(0) - , m_max_block_size_lg2(0) - , m_min_block_size_lg2(0) - , m_sb_count(0) - , m_hint_offset(0) - , m_data_offset(0) - , m_unused_padding(0) - {} + : m_tracker(), + m_sb_state_array(0), + m_sb_state_size(0), + m_sb_size_lg2(0), + m_max_block_size_lg2(0), + m_min_block_size_lg2(0), + m_sb_count(0), + m_hint_offset(0), + m_data_offset(0), + m_unused_padding(0) {} /**\brief Allocate a memory pool from 'memspace'. * @@ -349,221 +335,199 @@ public: * is also a power-of-two. These roundings are made to enable * significant runtime performance improvements. */ - MemoryPool( const base_memory_space & memspace - , const size_t min_total_alloc_size - , size_t min_block_alloc_size = 0 - , size_t max_block_alloc_size = 0 - , size_t min_superblock_size = 0 - ) - : m_tracker() - , m_sb_state_array(0) - , m_sb_state_size(0) - , m_sb_size_lg2(0) - , m_max_block_size_lg2(0) - , m_min_block_size_lg2(0) - , m_sb_count(0) - , m_hint_offset(0) - , m_data_offset(0) - , m_unused_padding(0) - { - const uint32_t int_align_lg2 = 3 ; /* align as int[8] */ - const uint32_t int_align_mask = ( 1u << int_align_lg2 ) - 1 ; - const uint32_t default_min_block_size = 1u << 6 ; /* 64 bytes */ - const uint32_t default_max_block_size = 1u << 12 ;/* 4k bytes */ - const uint32_t default_min_superblock_size = 1u << 20 ;/* 1M bytes */ - - //-------------------------------------------------- - // Default block and superblock sizes: - - if ( 0 == min_block_alloc_size ) { - // Default all sizes: - - min_superblock_size = - std::min( size_t(default_min_superblock_size) - , min_total_alloc_size ); - - min_block_alloc_size = - std::min( size_t(default_min_block_size) - , min_superblock_size ); - - max_block_alloc_size = - std::min( size_t(default_max_block_size) - , min_superblock_size ); - } - else if ( 0 == min_superblock_size ) { - - // Choose superblock size as minimum of: - // max_block_per_superblock * min_block_size - // max_superblock_size - // min_total_alloc_size + MemoryPool(const base_memory_space &memspace, + const size_t min_total_alloc_size, size_t min_block_alloc_size = 0, + size_t max_block_alloc_size = 0, size_t min_superblock_size = 0) + : m_tracker(), + m_sb_state_array(0), + m_sb_state_size(0), + m_sb_size_lg2(0), + m_max_block_size_lg2(0), + m_min_block_size_lg2(0), + m_sb_count(0), + m_hint_offset(0), + m_data_offset(0), + m_unused_padding(0) { + const uint32_t int_align_lg2 = 3; /* align as int[8] */ + const uint32_t int_align_mask = (1u << int_align_lg2) - 1; + const uint32_t default_min_block_size = 1u << 6; /* 64 bytes */ + const uint32_t default_max_block_size = 1u << 12; /* 4k bytes */ + const uint32_t default_min_superblock_size = 1u << 20; /* 1M bytes */ + + //-------------------------------------------------- + // Default block and superblock sizes: + + if (0 == min_block_alloc_size) { + // Default all sizes: + + min_superblock_size = + std::min(size_t(default_min_superblock_size), min_total_alloc_size); + + min_block_alloc_size = + std::min(size_t(default_min_block_size), min_superblock_size); + + max_block_alloc_size = + std::min(size_t(default_max_block_size), min_superblock_size); + } else if (0 == min_superblock_size) { + // Choose superblock size as minimum of: + // max_block_per_superblock * min_block_size + // max_superblock_size + // min_total_alloc_size + + const size_t max_superblock = + min_block_alloc_size * max_block_per_superblock; + + min_superblock_size = + std::min(max_superblock, + std::min(size_t(max_superblock_size), min_total_alloc_size)); + } - const size_t max_superblock = - min_block_alloc_size * max_block_per_superblock ; + if (0 == max_block_alloc_size) { + max_block_alloc_size = min_superblock_size; + } - min_superblock_size = - std::min( max_superblock , - std::min( size_t(max_superblock_size) - , min_total_alloc_size ) ); - } + //-------------------------------------------------- - if ( 0 == max_block_alloc_size ) { - max_block_alloc_size = min_superblock_size ; - } + /* Enforce size constraints: + * min_block_alloc_size <= max_block_alloc_size + * max_block_alloc_size <= min_superblock_size + * min_superblock_size <= max_superblock_size + * min_superblock_size <= min_total_alloc_size + * min_superblock_size <= min_block_alloc_size * + * max_block_per_superblock + */ - //-------------------------------------------------- - - /* Enforce size constraints: - * min_block_alloc_size <= max_block_alloc_size - * max_block_alloc_size <= min_superblock_size - * min_superblock_size <= max_superblock_size - * min_superblock_size <= min_total_alloc_size - * min_superblock_size <= min_block_alloc_size * - * max_block_per_superblock - */ - - Kokkos::Impl::memory_pool_bounds_verification - ( min_block_alloc_size - , max_block_alloc_size - , min_superblock_size - , max_superblock_size - , max_block_per_superblock - , min_total_alloc_size - ); + Kokkos::Impl::memory_pool_bounds_verification( + min_block_alloc_size, max_block_alloc_size, min_superblock_size, + max_superblock_size, max_block_per_superblock, min_total_alloc_size); - //-------------------------------------------------- - // Block and superblock size is power of two: - // Maximum value is 'max_superblock_size' + //-------------------------------------------------- + // Block and superblock size is power of two: + // Maximum value is 'max_superblock_size' - m_min_block_size_lg2 = + m_min_block_size_lg2 = Kokkos::Impl::integral_power_of_two_that_contains(min_block_alloc_size); - m_max_block_size_lg2 = + m_max_block_size_lg2 = Kokkos::Impl::integral_power_of_two_that_contains(max_block_alloc_size); - - m_sb_size_lg2 = + + m_sb_size_lg2 = Kokkos::Impl::integral_power_of_two_that_contains(min_superblock_size); - { - // number of superblocks is multiple of superblock size that - // can hold min_total_alloc_size. + { + // number of superblocks is multiple of superblock size that + // can hold min_total_alloc_size. - const uint64_t sb_size_mask = ( 1LU << m_sb_size_lg2 ) - 1 ; + const uint64_t sb_size_mask = (1LU << m_sb_size_lg2) - 1; - m_sb_count = ( min_total_alloc_size + sb_size_mask ) >> m_sb_size_lg2 ; - } + m_sb_count = (min_total_alloc_size + sb_size_mask) >> m_sb_size_lg2; + } - { - // Any superblock can be assigned to the smallest size block - // Size the block bitset to maximum number of blocks + { + // Any superblock can be assigned to the smallest size block + // Size the block bitset to maximum number of blocks - const uint32_t max_block_count_lg2 = - m_sb_size_lg2 - m_min_block_size_lg2 ; + const uint32_t max_block_count_lg2 = m_sb_size_lg2 - m_min_block_size_lg2; - m_sb_state_size = - ( CB::buffer_bound_lg2( max_block_count_lg2 ) + int_align_mask ) & ~int_align_mask ; - } + m_sb_state_size = + (CB::buffer_bound_lg2(max_block_count_lg2) + int_align_mask) & + ~int_align_mask; + } - // Array of all superblock states + // Array of all superblock states - const size_t all_sb_state_size = - ( m_sb_count * m_sb_state_size + int_align_mask ) & ~int_align_mask ; + const size_t all_sb_state_size = + (m_sb_count * m_sb_state_size + int_align_mask) & ~int_align_mask; - // Number of block sizes + // Number of block sizes - const int32_t number_block_sizes = - 1 + m_max_block_size_lg2 - m_min_block_size_lg2 ; + const int32_t number_block_sizes = + 1 + m_max_block_size_lg2 - m_min_block_size_lg2; - // Array length for possible block sizes - // Hint array is one uint32_t per block size + // Array length for possible block sizes + // Hint array is one uint32_t per block size - const int32_t block_size_array_size = - ( number_block_sizes + int_align_mask ) & ~int_align_mask ; + const int32_t block_size_array_size = + (number_block_sizes + int_align_mask) & ~int_align_mask; - m_hint_offset = all_sb_state_size ; - m_data_offset = m_hint_offset + - block_size_array_size * HINT_PER_BLOCK_SIZE ; + m_hint_offset = all_sb_state_size; + m_data_offset = m_hint_offset + block_size_array_size * HINT_PER_BLOCK_SIZE; - // Allocation: + // Allocation: - const size_t header_size = m_data_offset * sizeof(uint32_t); - const size_t alloc_size = header_size + - ( size_t(m_sb_count) << m_sb_size_lg2 ); + const size_t header_size = m_data_offset * sizeof(uint32_t); + const size_t alloc_size = + header_size + (size_t(m_sb_count) << m_sb_size_lg2); - Record * rec = Record::allocate( memspace , "MemoryPool" , alloc_size ); + Record *rec = Record::allocate(memspace, "MemoryPool", alloc_size); - m_tracker.assign_allocated_record_to_uninitialized( rec ); + m_tracker.assign_allocated_record_to_uninitialized(rec); - m_sb_state_array = (uint32_t *) rec->data(); + m_sb_state_array = (uint32_t *)rec->data(); - Kokkos::HostSpace host ; + Kokkos::HostSpace host; - uint32_t * const sb_state_array = - accessible ? m_sb_state_array - : (uint32_t *) host.allocate(header_size); + uint32_t *const sb_state_array = + accessible ? m_sb_state_array : (uint32_t *)host.allocate(header_size); - for ( int32_t i = 0 ; i < m_data_offset ; ++i ) sb_state_array[i] = 0 ; + for (int32_t i = 0; i < m_data_offset; ++i) sb_state_array[i] = 0; - // Initial assignment of empty superblocks to block sizes: + // Initial assignment of empty superblocks to block sizes: - for ( int32_t i = 0 ; i < number_block_sizes ; ++i ) { - const uint32_t block_size_lg2 = i + m_min_block_size_lg2 ; - const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2 ; - const uint32_t block_state = block_count_lg2 << state_shift ; - const uint32_t hint_begin = m_hint_offset + i * HINT_PER_BLOCK_SIZE ; + for (int32_t i = 0; i < number_block_sizes; ++i) { + const uint32_t block_size_lg2 = i + m_min_block_size_lg2; + const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2; + const uint32_t block_state = block_count_lg2 << state_shift; + const uint32_t hint_begin = m_hint_offset + i * HINT_PER_BLOCK_SIZE; - // for block size index 'i': - // sb_id_hint = sb_state_array[ hint_begin ]; - // sb_id_begin = sb_state_array[ hint_begin + 1 ]; + // for block size index 'i': + // sb_id_hint = sb_state_array[ hint_begin ]; + // sb_id_begin = sb_state_array[ hint_begin + 1 ]; - const int32_t jbeg = ( i * m_sb_count ) / number_block_sizes ; - const int32_t jend = ( ( i + 1 ) * m_sb_count ) / number_block_sizes ; + const int32_t jbeg = (i * m_sb_count) / number_block_sizes; + const int32_t jend = ((i + 1) * m_sb_count) / number_block_sizes; - sb_state_array[ hint_begin ] = uint32_t(jbeg); - sb_state_array[ hint_begin + 1 ] = uint32_t(jbeg); + sb_state_array[hint_begin] = uint32_t(jbeg); + sb_state_array[hint_begin + 1] = uint32_t(jbeg); - for ( int32_t j = jbeg ; j < jend ; ++j ) { - sb_state_array[ j * m_sb_state_size ] = block_state ; - } + for (int32_t j = jbeg; j < jend; ++j) { + sb_state_array[j * m_sb_state_size] = block_state; } + } - // Write out initialized state: + // Write out initialized state: - if ( ! accessible ) { - Kokkos::Impl::DeepCopy< base_memory_space , Kokkos::HostSpace > - ( m_sb_state_array , sb_state_array , header_size ); + if (!accessible) { + Kokkos::Impl::DeepCopy( + m_sb_state_array, sb_state_array, header_size); - host.deallocate( sb_state_array, header_size ); - } - else { - Kokkos::memory_fence(); - } + host.deallocate(sb_state_array, header_size); + } else { + Kokkos::memory_fence(); } + } //-------------------------------------------------------------------------- -private: - + private: /* Given a size 'n' get the block size in which it can be allocated. * Restrict lower bound to minimum block size. */ KOKKOS_FORCEINLINE_FUNCTION - uint32_t get_block_size_lg2( uint32_t n ) const noexcept - { - const unsigned i = Kokkos::Impl::integral_power_of_two_that_contains( n ); - - return i < m_min_block_size_lg2 ? m_min_block_size_lg2 : i ; - } + uint32_t get_block_size_lg2(uint32_t n) const noexcept { + const unsigned i = Kokkos::Impl::integral_power_of_two_that_contains(n); -public: + return i < m_min_block_size_lg2 ? m_min_block_size_lg2 : i; + } + public: /* Return 0 for invalid block size */ KOKKOS_INLINE_FUNCTION - uint32_t allocate_block_size( uint64_t alloc_size ) const noexcept - { - return alloc_size <= (1UL << m_max_block_size_lg2) - ? ( 1UL << get_block_size_lg2( uint32_t(alloc_size) ) ) - : 0 ; - } + uint32_t allocate_block_size(uint64_t alloc_size) const noexcept { + return alloc_size <= (1UL << m_max_block_size_lg2) + ? (1UL << get_block_size_lg2(uint32_t(alloc_size))) + : 0; + } //-------------------------------------------------------------------------- /**\brief Allocate a block of memory that is at least 'alloc_size' @@ -576,105 +540,98 @@ public: * The allocation attempt will try up to 'attempt_limit' times. */ KOKKOS_FUNCTION - void * allocate( size_t alloc_size - , int32_t attempt_limit = 1 ) const noexcept - { - if ( size_t(1LU << m_max_block_size_lg2) < alloc_size ) { - Kokkos::abort("Kokkos MemoryPool allocation request exceeded specified maximum allocation size"); - } + void *allocate(size_t alloc_size, int32_t attempt_limit = 1) const noexcept { + if (size_t(1LU << m_max_block_size_lg2) < alloc_size) { + Kokkos::abort( + "Kokkos MemoryPool allocation request exceeded specified maximum " + "allocation size"); + } - if ( 0 == alloc_size ) return (void*) 0 ; + if (0 == alloc_size) return (void *)0; - void * p = 0 ; + void *p = 0; - const uint32_t block_size_lg2 = get_block_size_lg2( alloc_size ); + const uint32_t block_size_lg2 = get_block_size_lg2(alloc_size); - // Allocation will fit within a superblock - // that has block sizes ( 1 << block_size_lg2 ) + // Allocation will fit within a superblock + // that has block sizes ( 1 << block_size_lg2 ) - const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2 ; - const uint32_t block_state = block_count_lg2 << state_shift ; - const uint32_t block_count = 1u << block_count_lg2 ; + const uint32_t block_count_lg2 = m_sb_size_lg2 - block_size_lg2; + const uint32_t block_state = block_count_lg2 << state_shift; + const uint32_t block_count = 1u << block_count_lg2; - // Superblock hints for this block size: - // hint_sb_id_ptr[0] is the dynamically changing hint - // hint_sb_id_ptr[1] is the static start point + // Superblock hints for this block size: + // hint_sb_id_ptr[0] is the dynamically changing hint + // hint_sb_id_ptr[1] is the static start point - volatile uint32_t * const hint_sb_id_ptr - = m_sb_state_array /* memory pool state array */ - + m_hint_offset /* offset to hint portion of array */ - + HINT_PER_BLOCK_SIZE /* number of hints per block size */ - * ( block_size_lg2 - m_min_block_size_lg2 ); /* block size id */ + volatile uint32_t *const hint_sb_id_ptr = + m_sb_state_array /* memory pool state array */ + + m_hint_offset /* offset to hint portion of array */ + + HINT_PER_BLOCK_SIZE /* number of hints per block size */ + * (block_size_lg2 - m_min_block_size_lg2); /* block size id */ - const int32_t sb_id_begin = int32_t( hint_sb_id_ptr[1] ); + const int32_t sb_id_begin = int32_t(hint_sb_id_ptr[1]); - // Fast query clock register 'tic' to pseudo-randomize - // the guess for which block within a superblock should - // be claimed. If not available then a search occurs. + // Fast query clock register 'tic' to pseudo-randomize + // the guess for which block within a superblock should + // be claimed. If not available then a search occurs. - const uint32_t block_id_hint = - (uint32_t)( Kokkos::Impl::clock_tic() -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA ) - // Spread out potentially concurrent access - // by threads within a warp or thread block. - + ( threadIdx.x + blockDim.x * threadIdx.y ) + const uint32_t block_id_hint = + (uint32_t)(Kokkos::Impl::clock_tic() +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA) + // Spread out potentially concurrent access + // by threads within a warp or thread block. + + (threadIdx.x + blockDim.x * threadIdx.y) #endif ); - // expected state of superblock for allocation - uint32_t sb_state = block_state ; - - int32_t sb_id = -1 ; + // expected state of superblock for allocation + uint32_t sb_state = block_state; - volatile uint32_t * sb_state_array = 0 ; + int32_t sb_id = -1; - while ( attempt_limit ) { + volatile uint32_t *sb_state_array = 0; - int32_t hint_sb_id = -1 ; + while (attempt_limit) { + int32_t hint_sb_id = -1; - if ( sb_id < 0 ) { + if (sb_id < 0) { + // No superblock specified, try the hint for this block size - // No superblock specified, try the hint for this block size + sb_id = hint_sb_id = int32_t(*hint_sb_id_ptr); - sb_id = hint_sb_id = int32_t( *hint_sb_id_ptr ); - - sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); - } - - // Require: - // 0 <= sb_id - // sb_state_array == m_sb_state_array + m_sb_state_size * sb_id + sb_state_array = m_sb_state_array + (sb_id * m_sb_state_size); + } - if ( sb_state == ( state_header_mask & *sb_state_array ) ) { + // Require: + // 0 <= sb_id + // sb_state_array == m_sb_state_array + m_sb_state_size * sb_id - // This superblock state is as expected, for the moment. - // Attempt to claim a bit. The attempt updates the state - // so have already made sure the state header is as expected. + if (sb_state == (state_header_mask & *sb_state_array)) { + // This superblock state is as expected, for the moment. + // Attempt to claim a bit. The attempt updates the state + // so have already made sure the state header is as expected. - const uint32_t count_lg2 = sb_state >> state_shift ; - const uint32_t mask = ( 1u << count_lg2 ) - 1 ; + const uint32_t count_lg2 = sb_state >> state_shift; + const uint32_t mask = (1u << count_lg2) - 1; - const Kokkos::pair result = - CB::acquire_bounded_lg2( sb_state_array - , count_lg2 - , block_id_hint & mask - , sb_state - ); + const Kokkos::pair result = CB::acquire_bounded_lg2( + sb_state_array, count_lg2, block_id_hint & mask, sb_state); - // If result.first < 0 then failed to acquire - // due to either full or buffer was wrong state. - // Could be wrong state if a deallocation raced the - // superblock to empty before the acquire could succeed. + // If result.first < 0 then failed to acquire + // due to either full or buffer was wrong state. + // Could be wrong state if a deallocation raced the + // superblock to empty before the acquire could succeed. - if ( 0 <= result.first ) { // acquired a bit + if (0 <= result.first) { // acquired a bit - const uint32_t size_lg2 = m_sb_size_lg2 - count_lg2 ; + const uint32_t size_lg2 = m_sb_size_lg2 - count_lg2; - // Set the allocated block pointer + // Set the allocated block pointer - p = ((char*)( m_sb_state_array + m_data_offset )) - + ( uint64_t(sb_id) << m_sb_size_lg2 ) // superblock memory - + ( uint64_t(result.first) << size_lg2 ); // block memory + p = ((char *)(m_sb_state_array + m_data_offset)) + + (uint64_t(sb_id) << m_sb_size_lg2) // superblock memory + + (uint64_t(result.first) << size_lg2); // block memory #if 0 printf( " MemoryPool(0x%lx) pointer(0x%lx) allocate(%lu) sb_id(%d) sb_state(0x%x) block_size(%d) block_capacity(%d) block_id(%d) block_claimed(%d)\n" @@ -689,146 +646,133 @@ public: , result.second ); #endif - break ; // Success - } + break; // Success } - //------------------------------------------------------------------ - // Arrive here if failed to acquire a block. - // Must find a new superblock. - - // Start searching at designated index for this block size. - // Look for superblock that, in preferential order, - // 1) part-full superblock of this block size - // 2) empty superblock to claim for this block size - // 3) part-full superblock of the next larger block size - - sb_state = block_state ; // Expect to find the desired state - sb_id = -1 ; - - bool update_hint = false ; - int32_t sb_id_empty = -1 ; - int32_t sb_id_large = -1 ; - uint32_t sb_state_large = 0 ; - - sb_state_array = m_sb_state_array + sb_id_begin * m_sb_state_size ; - - for ( int32_t i = 0 , id = sb_id_begin ; i < m_sb_count ; ++i ) { - - // Query state of the candidate superblock. - // Note that the state may change at any moment - // as concurrent allocations and deallocations occur. - - const uint32_t full_state = *sb_state_array ; - const uint32_t used = full_state & state_used_mask ; - const uint32_t state = full_state & state_header_mask ; + } + //------------------------------------------------------------------ + // Arrive here if failed to acquire a block. + // Must find a new superblock. - if ( state == block_state ) { + // Start searching at designated index for this block size. + // Look for superblock that, in preferential order, + // 1) part-full superblock of this block size + // 2) empty superblock to claim for this block size + // 3) part-full superblock of the next larger block size - // Superblock is assigned to this block size + sb_state = block_state; // Expect to find the desired state + sb_id = -1; - if ( used < block_count ) { + bool update_hint = false; + int32_t sb_id_empty = -1; + int32_t sb_id_large = -1; + uint32_t sb_state_large = 0; - // There is room to allocate one block + sb_state_array = m_sb_state_array + sb_id_begin * m_sb_state_size; - sb_id = id ; + for (int32_t i = 0, id = sb_id_begin; i < m_sb_count; ++i) { + // Query state of the candidate superblock. + // Note that the state may change at any moment + // as concurrent allocations and deallocations occur. - // Is there room to allocate more than one block? + const uint32_t full_state = *sb_state_array; + const uint32_t used = full_state & state_used_mask; + const uint32_t state = full_state & state_header_mask; - update_hint = used + 1 < block_count ; + if (state == block_state) { + // Superblock is assigned to this block size - break ; - } - } - else if ( 0 == used ) { + if (used < block_count) { + // There is room to allocate one block - // Superblock is empty + sb_id = id; - if ( -1 == sb_id_empty ) { + // Is there room to allocate more than one block? - // Superblock is not assigned to this block size - // and is the first empty superblock encountered. - // Save this id to use if a partfull superblock is not found. + update_hint = used + 1 < block_count; - sb_id_empty = id ; - } - } - else if ( ( -1 == sb_id_empty /* have not found an empty */ ) && - ( -1 == sb_id_large /* have not found a larger */ ) && - ( state < block_state /* a larger block */ ) && - // is not full: - ( used < ( 1u << ( state >> state_shift ) ) ) ) { - // First superblock encountered that is - // larger than this block size and - // has room for an allocation. - // Save this id to use of partfull or empty superblock not found - sb_id_large = id ; - sb_state_large = state ; + break; } + } else if (0 == used) { + // Superblock is empty - // Iterate around the superblock array: + if (-1 == sb_id_empty) { + // Superblock is not assigned to this block size + // and is the first empty superblock encountered. + // Save this id to use if a partfull superblock is not found. - if ( ++id < m_sb_count ) { - sb_state_array += m_sb_state_size ; - } - else { - id = 0 ; - sb_state_array = m_sb_state_array ; + sb_id_empty = id; } + } else if ((-1 == sb_id_empty /* have not found an empty */) && + (-1 == sb_id_large /* have not found a larger */) && + (state < block_state /* a larger block */) && + // is not full: + (used < (1u << (state >> state_shift)))) { + // First superblock encountered that is + // larger than this block size and + // has room for an allocation. + // Save this id to use of partfull or empty superblock not found + sb_id_large = id; + sb_state_large = state; } - // printf(" search m_sb_count(%d) sb_id(%d) sb_id_empty(%d) sb_id_large(%d)\n" , m_sb_count , sb_id , sb_id_empty , sb_id_large); + // Iterate around the superblock array: - if ( sb_id < 0 ) { + if (++id < m_sb_count) { + sb_state_array += m_sb_state_size; + } else { + id = 0; + sb_state_array = m_sb_state_array; + } + } - // Did not find a partfull superblock for this block size. + // printf(" search m_sb_count(%d) sb_id(%d) sb_id_empty(%d) + // sb_id_large(%d)\n" , m_sb_count , sb_id , sb_id_empty , sb_id_large); - if ( 0 <= sb_id_empty ) { + if (sb_id < 0) { + // Did not find a partfull superblock for this block size. - // Found first empty superblock following designated superblock - // Attempt to claim it for this block size. - // If the claim fails assume that another thread claimed it - // for this block size and try to use it anyway, - // but do not update hint. + if (0 <= sb_id_empty) { + // Found first empty superblock following designated superblock + // Attempt to claim it for this block size. + // If the claim fails assume that another thread claimed it + // for this block size and try to use it anyway, + // but do not update hint. - sb_id = sb_id_empty ; + sb_id = sb_id_empty; - sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); + sb_state_array = m_sb_state_array + (sb_id * m_sb_state_size); - // If successfully changed assignment of empty superblock 'sb_id' - // to this block_size then update the hint. + // If successfully changed assignment of empty superblock 'sb_id' + // to this block_size then update the hint. - const uint32_t state_empty = state_header_mask & *sb_state_array ; + const uint32_t state_empty = state_header_mask & *sb_state_array; - // If this thread claims the empty block then update the hint - update_hint = - state_empty == - Kokkos::atomic_compare_exchange - (sb_state_array,state_empty,block_state); - } - else if ( 0 <= sb_id_large ) { + // If this thread claims the empty block then update the hint + update_hint = + state_empty == Kokkos::atomic_compare_exchange( + sb_state_array, state_empty, block_state); + } else if (0 <= sb_id_large) { + // Found a larger superblock with space available - // Found a larger superblock with space available + sb_id = sb_id_large; + sb_state = sb_state_large; - sb_id = sb_id_large ; - sb_state = sb_state_large ; - - sb_state_array = m_sb_state_array + ( sb_id * m_sb_state_size ); - } - else { - // Did not find a potentially usable superblock - --attempt_limit ; - } + sb_state_array = m_sb_state_array + (sb_id * m_sb_state_size); + } else { + // Did not find a potentially usable superblock + --attempt_limit; } + } - if ( update_hint ) { - Kokkos::atomic_compare_exchange - ( hint_sb_id_ptr , uint32_t(hint_sb_id) , uint32_t(sb_id) ); - } - } // end allocation attempt loop - //-------------------------------------------------------------------- + if (update_hint) { + Kokkos::atomic_compare_exchange(hint_sb_id_ptr, uint32_t(hint_sb_id), + uint32_t(sb_id)); + } + } // end allocation attempt loop + //-------------------------------------------------------------------- - return p ; - } + return p; + } // end allocate //-------------------------------------------------------------------------- @@ -839,47 +783,43 @@ public: * For now the alloc_size is ignored. */ KOKKOS_INLINE_FUNCTION - void deallocate( void * p , size_t /* alloc_size */ ) const noexcept - { - if ( 0 == p ) return ; - - // Determine which superblock and block - const ptrdiff_t d = - ((char*)p) - ((char*)( m_sb_state_array + m_data_offset )); + void deallocate(void *p, size_t /* alloc_size */) const noexcept { + if (0 == p) return; - // Verify contained within the memory pool's superblocks: - const int ok_contains = - ( 0 <= d ) && ( size_t(d) < ( size_t(m_sb_count) << m_sb_size_lg2 ) ); + // Determine which superblock and block + const ptrdiff_t d = + ((char *)p) - ((char *)(m_sb_state_array + m_data_offset)); - int ok_block_aligned = 0 ; - int ok_dealloc_once = 0 ; + // Verify contained within the memory pool's superblocks: + const int ok_contains = + (0 <= d) && (size_t(d) < (size_t(m_sb_count) << m_sb_size_lg2)); - if ( ok_contains ) { + int ok_block_aligned = 0; + int ok_dealloc_once = 0; - const int sb_id = d >> m_sb_size_lg2 ; + if (ok_contains) { + const int sb_id = d >> m_sb_size_lg2; - // State array for the superblock. - volatile uint32_t * const sb_state_array = - m_sb_state_array + ( sb_id * m_sb_state_size ); + // State array for the superblock. + volatile uint32_t *const sb_state_array = + m_sb_state_array + (sb_id * m_sb_state_size); - const uint32_t block_state = (*sb_state_array) & state_header_mask ; - const uint32_t block_size_lg2 = - m_sb_size_lg2 - ( block_state >> state_shift ); + const uint32_t block_state = (*sb_state_array) & state_header_mask; + const uint32_t block_size_lg2 = + m_sb_size_lg2 - (block_state >> state_shift); - ok_block_aligned = 0 == ( d & ( ( 1UL << block_size_lg2 ) - 1 ) ); + ok_block_aligned = 0 == (d & ((1UL << block_size_lg2) - 1)); - if ( ok_block_aligned ) { + if (ok_block_aligned) { + // Map address to block's bit + // mask into superblock and then shift down for block index - // Map address to block's bit - // mask into superblock and then shift down for block index + const uint32_t bit = + (d & (ptrdiff_t(1LU << m_sb_size_lg2) - 1)) >> block_size_lg2; - const uint32_t bit = - ( d & ( ptrdiff_t( 1LU << m_sb_size_lg2 ) - 1 ) ) >> block_size_lg2 ; + const int result = CB::release(sb_state_array, bit, block_state); - const int result = - CB::release( sb_state_array , bit , block_state ); - - ok_dealloc_once = 0 <= result ; + ok_dealloc_once = 0 <= result; #if 0 printf( " MemoryPool(0x%lx) pointer(0x%lx) deallocate sb_id(%d) block_size(%d) block_capacity(%d) block_id(%d) block_claimed(%d)\n" @@ -891,10 +831,10 @@ public: , bit , result ); #endif - } } + } - if ( ! ok_contains || ! ok_block_aligned || ! ok_dealloc_once ) { + if (!ok_contains || !ok_block_aligned || !ok_dealloc_once) { #if 0 printf( " MemoryPool(0x%lx) pointer(0x%lx) deallocate ok_contains(%d) ok_block_aligned(%d) ok_dealloc_once(%d)\n" , (uintptr_t)m_sb_state_array @@ -903,44 +843,40 @@ public: , int(ok_block_aligned) , int(ok_dealloc_once) ); #endif - Kokkos::abort("Kokkos MemoryPool::deallocate given erroneous pointer"); - } + Kokkos::abort("Kokkos MemoryPool::deallocate given erroneous pointer"); } + } // end deallocate //-------------------------------------------------------------------------- KOKKOS_INLINE_FUNCTION - int number_of_superblocks() const noexcept { return m_sb_count ; } + int number_of_superblocks() const noexcept { return m_sb_count; } KOKKOS_INLINE_FUNCTION - void superblock_state( int sb_id - , int & block_size - , int & block_count_capacity - , int & block_count_used ) const noexcept - { - block_size = 0 ; - block_count_capacity = 0 ; - block_count_used = 0 ; - - if ( Kokkos::Impl::MemorySpaceAccess - < Kokkos::Impl::ActiveExecutionMemorySpace - , base_memory_space >::accessible ) { - // Can access the state array - - const uint32_t state = - ((uint32_t volatile *)m_sb_state_array)[sb_id*m_sb_state_size]; - - const uint32_t block_count_lg2 = state >> state_shift ; - const uint32_t block_used = state & state_used_mask ; - - block_size = 1LU << ( m_sb_size_lg2 - block_count_lg2 ); - block_count_capacity = 1LU << block_count_lg2 ; - block_count_used = block_used ; - } + void superblock_state(int sb_id, int &block_size, int &block_count_capacity, + int &block_count_used) const noexcept { + block_size = 0; + block_count_capacity = 0; + block_count_used = 0; + + if (Kokkos::Impl::MemorySpaceAccess< + Kokkos::Impl::ActiveExecutionMemorySpace, + base_memory_space>::accessible) { + // Can access the state array + + const uint32_t state = + ((uint32_t volatile *)m_sb_state_array)[sb_id * m_sb_state_size]; + + const uint32_t block_count_lg2 = state >> state_shift; + const uint32_t block_used = state & state_used_mask; + + block_size = 1LU << (m_sb_size_lg2 - block_count_lg2); + block_count_capacity = 1LU << block_count_lg2; + block_count_used = block_used; } + } }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_MEMORYPOOL_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp b/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp index 509ac6499e..75d3d40144 100644 --- a/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp +++ b/lib/kokkos/core/src/Kokkos_MemoryTraits.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -59,53 +60,64 @@ namespace Kokkos { * A zero value is the default for a View, indicating that none of * these traits are present. */ -enum MemoryTraitsFlags - { Unmanaged = 0x01 - , RandomAccess = 0x02 - , Atomic = 0x04 - , Restrict = 0x08 - , Aligned = 0x10 - }; +enum MemoryTraitsFlags { + Unmanaged = 0x01, + RandomAccess = 0x02, + Atomic = 0x04, + Restrict = 0x08, + Aligned = 0x10 +}; -template < unsigned T > +template struct MemoryTraits { //! Tag this class as a kokkos memory traits: - typedef MemoryTraits memory_traits ; + typedef MemoryTraits memory_traits; #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - enum : bool { Unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) }; - enum : bool { RandomAccess = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) }; - enum : bool { Atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; - enum : bool { Restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) }; - enum : bool { Aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; + enum : bool { + Unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) + }; + enum : bool { + RandomAccess = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) + }; + enum : bool { Atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; + enum : bool { Restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) }; + enum : bool { Aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; #endif - enum : bool { is_unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) }; - enum : bool { is_random_access = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) }; - enum : bool { is_atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; - enum : bool { is_restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) }; - enum : bool { is_aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; + enum : bool { + is_unmanaged = (unsigned(0) != (T & unsigned(Kokkos::Unmanaged))) + }; + enum : bool { + is_random_access = (unsigned(0) != (T & unsigned(Kokkos::RandomAccess))) + }; + enum : bool { is_atomic = (unsigned(0) != (T & unsigned(Kokkos::Atomic))) }; + enum : bool { + is_restrict = (unsigned(0) != (T & unsigned(Kokkos::Restrict))) + }; + enum : bool { is_aligned = (unsigned(0) != (T & unsigned(Kokkos::Aligned))) }; }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -typedef Kokkos::MemoryTraits<0> MemoryManaged ; -typedef Kokkos::MemoryTraits< Kokkos::Unmanaged > MemoryUnmanaged ; -typedef Kokkos::MemoryTraits< Kokkos::Unmanaged | Kokkos::RandomAccess > MemoryRandomAccess ; +typedef Kokkos::MemoryTraits<0> MemoryManaged; +typedef Kokkos::MemoryTraits MemoryUnmanaged; +typedef Kokkos::MemoryTraits + MemoryRandomAccess; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { namespace Impl { -static_assert( - ( 0 < int(KOKKOS_MEMORY_ALIGNMENT) ) && - ( 0 == ( int(KOKKOS_MEMORY_ALIGNMENT) & (int(KOKKOS_MEMORY_ALIGNMENT)-1))) , - "KOKKOS_MEMORY_ALIGNMENT must be a power of two" ); +static_assert((0 < int(KOKKOS_MEMORY_ALIGNMENT)) && + (0 == (int(KOKKOS_MEMORY_ALIGNMENT) & + (int(KOKKOS_MEMORY_ALIGNMENT) - 1))), + "KOKKOS_MEMORY_ALIGNMENT must be a power of two"); /** \brief Memory alignment settings * @@ -113,13 +125,12 @@ static_assert( * Enable compatibility of views from different devices with static stride. * Use compiler flag to enable overwrites. */ -enum : unsigned - { MEMORY_ALIGNMENT = KOKKOS_MEMORY_ALIGNMENT - , MEMORY_ALIGNMENT_THRESHOLD = KOKKOS_MEMORY_ALIGNMENT_THRESHOLD - }; +enum : unsigned { + MEMORY_ALIGNMENT = KOKKOS_MEMORY_ALIGNMENT, + MEMORY_ALIGNMENT_THRESHOLD = KOKKOS_MEMORY_ALIGNMENT_THRESHOLD +}; -} //namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif /* #ifndef KOKKOS_MEMORYTRAITS_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_NumericTraits.hpp b/lib/kokkos/core/src/Kokkos_NumericTraits.hpp index baac782545..666bb33266 100644 --- a/lib/kokkos/core/src/Kokkos_NumericTraits.hpp +++ b/lib/kokkos/core/src/Kokkos_NumericTraits.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -44,176 +45,347 @@ #ifndef KOKKOS_NUMERICTRAITS_HPP #define KOKKOS_NUMERICTRAITS_HPP -#include -#include +#include +#include namespace Kokkos { -template +template struct reduction_identity; /*{ KOKKOS_FORCEINLINE_FUNCTION constexpr static T sum() { return T(); } // 0 KOKKOS_FORCEINLINE_FUNCTION constexpr static T prod() // 1 - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom prod reduction type"); return T(); } + { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom prod reduction type"); return T(); } KOKKOS_FORCEINLINE_FUNCTION constexpr static T max() // minimum value - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom max reduction type"); return T(); } + { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom max reduction type"); return T(); } KOKKOS_FORCEINLINE_FUNCTION constexpr static T min() // maximum value - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom min reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T bor() // 0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom bor reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T band() // !0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom band reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T lor() // 0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom lor reduction type"); return T(); } - KOKKOS_FORCEINLINE_FUNCTION constexpr static T land() // !0, only for integer type - { static_assert( false, "Missing specialization of Kokkos::reduction_identity for custom land reduction type"); return T(); } + { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom min reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T bor() // 0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom bor reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T band() // !0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom band reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T lor() // 0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom lor reduction type"); return T(); } + KOKKOS_FORCEINLINE_FUNCTION constexpr static T land() // !0, only for integer +type { static_assert( false, "Missing specialization of +Kokkos::reduction_identity for custom land reduction type"); return T(); } };*/ -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char max() {return SCHAR_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char min() {return SCHAR_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char max() { + return SCHAR_MIN; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char min() { + return SCHAR_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static signed char land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static short sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short max() {return SHRT_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short min() {return SHRT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static short land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static short sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short max() { return SHRT_MIN; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short min() { return SHRT_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static short land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static int sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int max() {return INT_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int min() {return INT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static int land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static int sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int max() { return INT_MIN; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int min() { return INT_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static int land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long max() {return LLONG_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long min() {return LLONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long max() { return LLONG_MIN; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long min() { return LLONG_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long max() {return LLONG_MIN;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long min() {return LLONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long max() { + return LLONG_MIN; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long min() { + return LLONG_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char min() {return UCHAR_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char min() { + return UCHAR_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned char land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short min() {return USHRT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short min() { + return USHRT_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned short land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int min() {return UINT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int min() { + return UINT_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned int land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long min() {return ULONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long min() { + return ULONG_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long sum() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long prod() {return static_cast(1);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long max() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long min() {return ULLONG_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long bor() {return static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long band() {return ~static_cast(0x0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long lor() {return static_cast(0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long land() {return static_cast(1);} + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long sum() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long prod() { + return static_cast(1); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long max() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long min() { + return ULLONG_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long bor() { + return static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long band() { + return ~static_cast(0x0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long lor() { + return static_cast(0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static unsigned long long land() { + return static_cast(1); + } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static float sum() {return static_cast(0.0f);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static float prod() {return static_cast(1.0f);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static float max() {return -FLT_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static float min() {return FLT_MAX;} + KOKKOS_FORCEINLINE_FUNCTION constexpr static float sum() { + return static_cast(0.0f); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static float prod() { + return static_cast(1.0f); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static float max() { return -FLT_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static float min() { return FLT_MAX; } }; -template<> +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static double sum() {return static_cast(0.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static double prod() {return static_cast(1.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static double max() {return -DBL_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static double min() {return DBL_MAX;} + KOKKOS_FORCEINLINE_FUNCTION constexpr static double sum() { + return static_cast(0.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static double prod() { + return static_cast(1.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static double max() { return -DBL_MAX; } + KOKKOS_FORCEINLINE_FUNCTION constexpr static double min() { return DBL_MAX; } }; -#if !defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA ) -template<> +#if !defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_CUDA) +template <> struct reduction_identity { - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double sum() {return static_cast(0.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double prod() {return static_cast(1.0);} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double max() {return -LDBL_MAX;} - KOKKOS_FORCEINLINE_FUNCTION constexpr static long double min() {return LDBL_MAX;} + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double sum() { + return static_cast(0.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double prod() { + return static_cast(1.0); + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double max() { + return -LDBL_MAX; + } + KOKKOS_FORCEINLINE_FUNCTION constexpr static long double min() { + return LDBL_MAX; + } }; #endif -} +} // namespace Kokkos #endif diff --git a/lib/kokkos/core/src/Kokkos_OpenMP.hpp b/lib/kokkos/core/src/Kokkos_OpenMP.hpp index 6ee8f08dc8..3955c06156 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMP.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMP.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_OPENMP_HPP #include -#if defined( KOKKOS_ENABLE_OPENMP) +#if defined(KOKKOS_ENABLE_OPENMP) #include @@ -76,53 +77,48 @@ class OpenMPExec; /// \class OpenMP /// \brief Kokkos device for multicore processors in the host memory space. class OpenMP { -public: + public: //! Tag this class as a kokkos execution space using execution_space = OpenMP; using memory_space = - #ifdef KOKKOS_ENABLE_HBWSPACE - Experimental::HBWSpace; - #else - HostSpace; - #endif +#ifdef KOKKOS_ENABLE_HBWSPACE + Experimental::HBWSpace; +#else + HostSpace; +#endif //! This execution space preferred device_type - using device_type = Kokkos::Device< execution_space, memory_space >; + using device_type = Kokkos::Device; using array_layout = LayoutRight; using size_type = memory_space::size_type; - using scratch_memory_space = ScratchMemorySpace< OpenMP >; + using scratch_memory_space = ScratchMemorySpace; /// \brief Get a handle to the default execution space instance - inline - OpenMP() noexcept; + inline OpenMP() noexcept; /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool verbose = false ); + static void print_configuration(std::ostream&, const bool verbose = false); /// \brief is the instance running a parallel algorithm - inline - static bool in_parallel( OpenMP const& = OpenMP() ) noexcept; + inline static bool in_parallel(OpenMP const& = OpenMP()) noexcept; /// \brief Wait until all dispatched functors complete on the given instance /// /// This is a no-op on OpenMP - static void impl_static_fence( OpenMP const& = OpenMP() ) noexcept; + static void impl_static_fence(OpenMP const& = OpenMP()) noexcept; - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - static void fence( OpenMP const& = OpenMP() ) noexcept; - #else +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE + static void fence(OpenMP const& = OpenMP()) noexcept; +#else void fence() const; - #endif - +#endif /// \brief Does the given instance return immediately after launching /// a parallel algorithm /// /// This always returns false on OpenMP - inline - static bool is_asynchronous( OpenMP const& = OpenMP() ) noexcept; - + inline static bool is_asynchronous(OpenMP const& = OpenMP()) noexcept; /// \brief Partition the default instance into new instances without creating /// new masters @@ -137,24 +133,22 @@ public: /// This is a no-op on OpenMP since a non default instance cannot be created static OpenMP create_instance(...); - /// \brief Partition the default instance and call 'f' on each new 'master' thread + /// \brief Partition the default instance and call 'f' on each new 'master' + /// thread /// /// Func is a functor with the following signiture /// void( int partition_id, int num_partitions ) template - static void partition_master( F const& f - , int requested_num_partitions = 0 - , int requested_partition_size = 0 - ); + static void partition_master(F const& f, int requested_num_partitions = 0, + int requested_partition_size = 0); // use UniqueToken static int concurrency(); #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /// \brief Initialize the default execution space - static void initialize( int thread_count, - int use_numa_count, - int use_cores_per_numa = 0); + static void initialize(int thread_count, int use_numa_count, + int use_cores_per_numa = 0); /// \brief Initialize the default execution space /// @@ -166,66 +160,62 @@ public: /// if ( thread_count > 0 ) /// then force openmp to use the given number of threads and change /// the default number of threads - static void initialize( int thread_count = -1 ); + static void initialize(int thread_count = -1); - /// \brief is the default execution space initialized for current 'master' thread + /// \brief is the default execution space initialized for current 'master' + /// thread static bool is_initialized() noexcept; /// \brief Free any resources being consumed by the default execution space static void finalize(); - inline - static int thread_pool_size() noexcept; + inline static int thread_pool_size() noexcept; /** \brief The rank of the executing thread in this thread pool */ KOKKOS_INLINE_FUNCTION static int thread_pool_rank() noexcept; - inline - static int thread_pool_size( int depth ); + inline static int thread_pool_size(int depth); - static void sleep() {}; - static void wake() {}; + static void sleep(){}; + static void wake(){}; // Using omp_get_max_threads(); is problematic // On Intel (essentially an initial call to the OpenMP runtime // without a parallel region before will set a process mask for a single core - // The runtime will than bind threads for a parallel region to other cores on the - // entering the first parallel region and make the process mask the aggregate of - // the thread masks. The intend seems to be to make serial code run fast, if you - // compile with OpenMP enabled but don't actually use parallel regions or so - // static int omp_max_threads = omp_get_max_threads(); + // The runtime will than bind threads for a parallel region to other cores on + // the entering the first parallel region and make the process mask the + // aggregate of the thread masks. The intend seems to be to make serial code + // run fast, if you compile with OpenMP enabled but don't actually use + // parallel regions or so static int omp_max_threads = omp_get_max_threads(); static int get_current_max_threads() noexcept; // use UniqueToken - inline - static int max_hardware_threads() noexcept; + inline static int max_hardware_threads() noexcept; // use UniqueToken KOKKOS_INLINE_FUNCTION static int hardware_thread_id() noexcept; #else - static void impl_initialize( int thread_count = -1 ); + static void impl_initialize(int thread_count = -1); - /// \brief is the default execution space initialized for current 'master' thread + /// \brief is the default execution space initialized for current 'master' + /// thread static bool impl_is_initialized() noexcept; /// \brief Free any resources being consumed by the default execution space static void impl_finalize(); - inline - static int impl_thread_pool_size() noexcept; + inline static int impl_thread_pool_size() noexcept; /** \brief The rank of the executing thread in this thread pool */ KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() noexcept; - inline - static int impl_thread_pool_size( int depth ); + inline static int impl_thread_pool_size(int depth); // use UniqueToken - inline - static int impl_max_hardware_threads() noexcept; + inline static int impl_max_hardware_threads() noexcept; // use UniqueToken KOKKOS_INLINE_FUNCTION @@ -237,7 +227,7 @@ public: static constexpr const char* name() noexcept { return "OpenMP"; } }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -245,30 +235,24 @@ public: namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::OpenMP::memory_space - , Kokkos::OpenMP::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::OpenMP::memory_space - , Kokkos::OpenMP::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::OpenMP::memory_space, Kokkos::OpenMP::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -283,4 +267,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_OPENMP ) && defined( _OPENMP ) */ #endif /* #ifndef KOKKOS_OPENMP_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp b/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp index e2dd249ff7..9706751f9c 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMPTarget.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,7 +47,7 @@ #include -#if defined( KOKKOS_ENABLE_OPENMPTARGET ) && defined( _OPENMP ) +#if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(_OPENMP) #include @@ -67,21 +68,21 @@ namespace Experimental { /// \class OpenMPTarget /// \brief Kokkos device for multicore processors in the host memory space. class OpenMPTarget { -public: + public: //------------------------------------ //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as a kokkos execution space - typedef OpenMPTarget execution_space ; - typedef OpenMPTargetSpace memory_space ; + typedef OpenMPTarget execution_space; + typedef OpenMPTargetSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; - typedef LayoutLeft array_layout ; - typedef memory_space::size_type size_type ; + typedef LayoutLeft array_layout; + typedef memory_space::size_type size_type; - typedef ScratchMemorySpace< OpenMPTarget > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; //@} //------------------------------------ @@ -96,11 +97,12 @@ public: /** \brief Wake the device from the 'sleep' state. A noop for OpenMPTarget. */ static bool wake(); - /** \brief Wait until all dispatched functors complete. A noop for OpenMPTarget. */ + /** \brief Wait until all dispatched functors complete. A noop for + * OpenMPTarget. */ static void fence() {} /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); /// \brief Free any resources being consumed by the device. static void finalize(); @@ -114,9 +116,8 @@ public: * 2) Allocate a HostThread for each OpenMPTarget thread to hold its * topology and fan in/out data. */ - static void initialize( unsigned thread_count = 0 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 ); + static void initialize(unsigned thread_count = 0, unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0); static int is_initialized(); @@ -125,14 +126,16 @@ public: //@} //------------------------------------ - /** \brief This execution space has a topological thread pool which can be queried. + /** \brief This execution space has a topological thread pool which can be + * queried. * - * All threads within a pool have a common memory space for which they are cache coherent. - * depth = 0 gives the number of threads in the whole pool. - * depth = 1 gives the number of threads in a NUMA region, typically sharing L3 cache. - * depth = 2 gives the number of threads at the finest granularity, typically sharing L1 cache. + * All threads within a pool have a common memory space for which they are + * cache coherent. depth = 0 gives the number of threads in the whole pool. + * depth = 1 gives the number of threads in a NUMA region, typically + * sharing L3 cache. depth = 2 gives the number of threads at the finest + * granularity, typically sharing L1 cache. */ - inline static int thread_pool_size( int depth = 0 ); + inline static int thread_pool_size(int depth = 0); /** \brief The rank of the executing thread in this thread pool */ KOKKOS_INLINE_FUNCTION static int thread_pool_rank(); @@ -141,15 +144,17 @@ public: inline static unsigned max_hardware_threads() { return thread_pool_size(0); } - KOKKOS_INLINE_FUNCTION static - unsigned hardware_thread_id() { return thread_pool_rank(); } + KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { + return thread_pool_rank(); + } static const char* name(); -private: + + private: static bool m_is_initialized; }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -157,19 +162,17 @@ private: namespace Kokkos { namespace Impl { -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Experimental::OpenMPTarget::memory_space - , Kokkos::Experimental::OpenMPTarget::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Experimental::OpenMPTarget::memory_space, + Kokkos::Experimental::OpenMPTarget::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -182,5 +185,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_OPENMPTARGET ) && defined( _OPENMP ) */ #endif /* #ifndef KOKKOS_OPENMPTARGET_HPP */ - - diff --git a/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp b/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp index abb0b8588d..96c46754b4 100644 --- a/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_OpenMPTargetSpace.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -66,25 +67,25 @@ namespace Impl { /// where the hash value is derived from the address of the /// object for which an atomic operation is performed. /// This function initializes the locks to zero (unset). -//void init_lock_array_host_space(); +// void init_lock_array_host_space(); -/// \brief Acquire a lock for the address +/// \brief Aquire a lock for the address /// -/// This function tries to acquire the lock for the hash value derived -/// from the provided ptr. If the lock is successfully acquired the +/// This function tries to aquire the lock for the hash value derived +/// from the provided ptr. If the lock is successfully aquired the /// function returns true. Otherwise it returns false. -//bool lock_address_host_space(void* ptr); +// bool lock_address_host_space(void* ptr); /// \brief Release lock for the address /// /// This function releases the lock for the hash value derived /// from the provided ptr. This function should only be called -/// after previously successfully acquiring a lock with +/// after previously successfully aquiring a lock with /// lock_address. -//void unlock_address_host_space(void* ptr); +// void unlock_address_host_space(void* ptr); -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos namespace Kokkos { namespace Experimental { @@ -95,11 +96,10 @@ namespace Experimental { /// OpenMPTargetSpace is a memory space that governs host memory. "Host" /// memory means the usual CPU-accessible memory. class OpenMPTargetSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef OpenMPTargetSpace memory_space ; - typedef size_t size_type ; + typedef OpenMPTargetSpace memory_space; + typedef size_t size_type; /// \typedef execution_space /// \brief Default execution space for this memory space. @@ -107,34 +107,33 @@ public: /// Every memory space has a default execution space. This is /// useful for things like initializing a View (which happens in /// parallel using the View's default execution space). - typedef Kokkos::Experimental::OpenMPTarget execution_space ; + typedef Kokkos::Experimental::OpenMPTarget execution_space; //! This memory space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; /*--------------------------------*/ /**\brief Default memory space instance */ OpenMPTargetSpace(); - OpenMPTargetSpace( OpenMPTargetSpace && rhs ) = default ; - OpenMPTargetSpace( const OpenMPTargetSpace & rhs ) = default ; - OpenMPTargetSpace & operator = ( OpenMPTargetSpace && ) = default ; - OpenMPTargetSpace & operator = ( const OpenMPTargetSpace & ) = default ; - ~OpenMPTargetSpace() = default ; + OpenMPTargetSpace(OpenMPTargetSpace&& rhs) = default; + OpenMPTargetSpace(const OpenMPTargetSpace& rhs) = default; + OpenMPTargetSpace& operator=(OpenMPTargetSpace&&) = default; + OpenMPTargetSpace& operator=(const OpenMPTargetSpace&) = default; + ~OpenMPTargetSpace() = default; /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; - -private: + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::Experimental::OpenMPTargetSpace , void > ; + private: + friend class Kokkos::Impl::SharedAllocationRecord< + Kokkos::Experimental::OpenMPTargetSpace, void>; }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -142,70 +141,62 @@ private: namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::Experimental::OpenMPTargetSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: - - friend Kokkos::Experimental::OpenMPTargetSpace ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + friend Kokkos::Experimental::OpenMPTargetSpace; - typedef SharedAllocationRecord< void , void > RecordBase ; + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); - /**\brief Root record for tracked allocations from this OpenMPTargetSpace instance */ - static RecordBase s_root_record ; + /**\brief Root record for tracked allocations from this OpenMPTargetSpace + * instance */ + static RecordBase s_root_record; - const Kokkos::Experimental::OpenMPTargetSpace m_space ; - -protected: + const Kokkos::Experimental::OpenMPTargetSpace m_space; + protected: ~SharedAllocationRecord(); - SharedAllocationRecord() = default ; - - SharedAllocationRecord( const Kokkos::Experimental::OpenMPTargetSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord() = default; -public: + SharedAllocationRecord( + const Kokkos::Experimental::OpenMPTargetSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); + public: std::string get_label() const; - KOKKOS_INLINE_FUNCTION static - SharedAllocationRecord * allocate( const Kokkos::Experimental::OpenMPTargetSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + KOKKOS_INLINE_FUNCTION static SharedAllocationRecord* allocate( + const Kokkos::Experimental::OpenMPTargetSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::OpenMPTargetSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked( + const Kokkos::Experimental::OpenMPTargetSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); - + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream & , const Kokkos::Experimental::OpenMPTargetSpace & , bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::OpenMPTargetSpace&, + bool detail = false); }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -213,53 +204,59 @@ public: namespace Kokkos { namespace Impl { -//TODO: implement all possible deep_copies -template -struct DeepCopy { - DeepCopy( void * dst , const void * src , size_t n ) { - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_default_device()); +// TODO: implement all possible deep_copies +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_default_device()); } - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_default_device()); + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_default_device()); } }; - -template -struct DeepCopy { - DeepCopy( void * dst , const void * src , size_t n ) { - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_initial_device()); +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_initial_device()); } - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_default_device(), omp_get_initial_device()); + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_default_device(), omp_get_initial_device()); } }; -template -struct DeepCopy { - DeepCopy( void * dst , const void * src , size_t n ) { - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_initial_device(), omp_get_default_device()); +template +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t n) { + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_initial_device(), omp_get_default_device()); } - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) { + DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, size_t n) { exec.fence(); - omp_target_memcpy( dst , const_cast (src) , n, 0, 0, omp_get_initial_device(), omp_get_default_device()); + omp_target_memcpy(dst, const_cast(src), n, 0, 0, + omp_get_initial_device(), omp_get_default_device()); } }; - -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experimental::OpenMPTargetSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::HostSpace, Kokkos::Experimental::OpenMPTargetSpace> { enum { value = false }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos #endif #endif /* #define KOKKOS_OPENMPTARGETSPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Pair.hpp b/lib/kokkos/core/src/Kokkos_Pair.hpp index ab0ab8152a..ee9797b4b3 100644 --- a/lib/kokkos/core/src/Kokkos_Pair.hpp +++ b/lib/kokkos/core/src/Kokkos_Pair.hpp @@ -1,10 +1,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -22,10 +23,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -61,15 +62,14 @@ namespace Kokkos { /// implements the same interface as std::pair, but can be used on a /// CUDA device as well as on the host. template -struct pair -{ +struct pair { //! The first template parameter of this class. typedef T1 first_type; //! The second template parameter of this class. typedef T2 second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -80,54 +80,48 @@ struct pair /// public. KOKKOS_FORCEINLINE_FUNCTION constexpr #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - pair() : first(), second() {} + pair() + : first(), second() { + } #else - pair() = default; + pair() = default; #endif /// \brief Constructor that takes both elements of the pair. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type const& f, second_type const& s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type const& f, + second_type const& s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const volatile pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const volatile pair& p) + : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=(const pair& p) { + first = p.first; second = p.second; return *this; } - /// \brief Assignment operator, for volatile *this. /// /// \param p [in] Input; right-hand side of the assignment. @@ -140,10 +134,9 @@ struct pair /// practice, this means that you should not chain assignments with /// volatile lvalues. template - KOKKOS_FORCEINLINE_FUNCTION - void operator=(const volatile pair &p) volatile - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION void operator=( + const volatile pair& p) volatile { + first = p.first; second = p.second; // We deliberately do not return anything here. See explanation // in public documentation above. @@ -151,9 +144,7 @@ struct pair // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Return the std::pair version of this object. /// @@ -164,20 +155,20 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; template -struct pair -{ +struct pair { //! The first template parameter of this class. typedef T1& first_type; //! The second template parameter of this class. typedef T2& second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -185,36 +176,29 @@ struct pair /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type f, second_type s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type f, second_type s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { + first = p.first; second = p.second; return *this; } @@ -228,20 +212,20 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; template -struct pair -{ +struct pair { //! The first template parameter of this class. - typedef T1 first_type; + typedef T1 first_type; //! The second template parameter of this class. typedef T2& second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -249,36 +233,29 @@ struct pair /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type const& f, second_type s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type const& f, second_type s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { + first = p.first; second = p.second; return *this; } @@ -292,20 +269,20 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; template -struct pair -{ +struct pair { //! The first template parameter of this class. - typedef T1& first_type; + typedef T1& first_type; //! The second template parameter of this class. typedef T2 second_type; //! The first element of the pair. - first_type first; + first_type first; //! The second element of the pair. second_type second; @@ -313,36 +290,29 @@ struct pair /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(first_type f, second_type const& s) - : first(f), second(s) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(first_type f, second_type const& s) + : first(f), second(s) {} /// \brief Copy constructor. /// /// This calls the copy constructors of T1 and T2. It won't compile /// if those copy constructors are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first), second(p.second) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first), second(p.second) {} // from std::pair template - pair( const std::pair &p) - : first(p.first), second(p.second) - {} + pair(const std::pair& p) : first(p.first), second(p.second) {} /// \brief Assignment operator. /// /// This calls the assignment operators of T1 and T2. It won't /// compile if the assignment operators are not defined and public. template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { - first = p.first; + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { + first = p.first; second = p.second; return *this; } @@ -356,54 +326,62 @@ struct pair /// \note This is not a conversion operator, since defining a /// conversion operator made the relational operators have /// ambiguous definitions. - std::pair to_std_pair() const - { return std::make_pair(first,second); } + std::pair to_std_pair() const { + return std::make_pair(first, second); + } }; //! Equality operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION -bool operator== (const pair& lhs, const pair& rhs) -{ return lhs.first==rhs.first && lhs.second==rhs.second; } +KOKKOS_FORCEINLINE_FUNCTION bool operator==(const pair& lhs, + const pair& rhs) { + return lhs.first == rhs.first && lhs.second == rhs.second; +} //! Inequality operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator!= (const pair& lhs, const pair& rhs) -{ return !(lhs==rhs); } +KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator!=(const pair& lhs, + const pair& rhs) { + return !(lhs == rhs); +} //! Less-than operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator< (const pair& lhs, const pair& rhs) -{ return lhs.first& lhs, + const pair& rhs) { + return lhs.first < rhs.first || + (!(rhs.first < lhs.first) && lhs.second < rhs.second); +} //! Less-than-or-equal-to operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator<= (const pair& lhs, const pair& rhs) -{ return !(rhs& lhs, + const pair& rhs) { + return !(rhs < lhs); +} //! Greater-than operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator> (const pair& lhs, const pair& rhs) -{ return rhs(const pair& lhs, + const pair& rhs) { + return rhs < lhs; +} //! Greater-than-or-equal-to operator for Kokkos::pair. template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator>= (const pair& lhs, const pair& rhs) -{ return !(lhs=(const pair& lhs, + const pair& rhs) { + return !(lhs < rhs); +} /// \brief Return a new pair. /// /// This is a "nonmember constructor" for Kokkos::pair. It works just /// like std::make_pair. -template -KOKKOS_FORCEINLINE_FUNCTION constexpr -pair make_pair (T1 x, T2 y) -{ return ( pair(x,y) ); } +template +KOKKOS_FORCEINLINE_FUNCTION constexpr pair make_pair(T1 x, T2 y) { + return (pair(x, y)); +} /// \brief Return a pair of references to the input arguments. /// @@ -444,51 +422,44 @@ pair make_pair (T1 x, T2 y) /// element of the pair. The latter could be significant if one or /// both elements of the pair are more substantial objects than \c int /// or \c bool. -template -KOKKOS_FORCEINLINE_FUNCTION -pair tie (T1 & x, T2 & y) -{ return ( pair(x,y) ); } +template +KOKKOS_FORCEINLINE_FUNCTION pair tie(T1& x, T2& y) { + return (pair(x, y)); +} // // Specialization of Kokkos::pair for a \c void second argument. This // is not actually a "pair"; it only contains one element, the first. // template -struct pair -{ +struct pair { typedef T1 first_type; typedef void second_type; - first_type first; + first_type first; enum { second = 0 }; KOKKOS_FORCEINLINE_FUNCTION constexpr #ifdef KOKKOS_CUDA_9_DEFAULTED_BUG_WORKAROUND - pair() : first() {} + pair() + : first() { + } #else - pair() = default; + pair() = default; #endif - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(const first_type & f) - : first(f) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const first_type& f) : first(f) {} - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair(const first_type & f, int) - : first(f) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const first_type& f, int) + : first(f) {} template - KOKKOS_FORCEINLINE_FUNCTION constexpr - pair( const pair &p) - : first(p.first) - {} + KOKKOS_FORCEINLINE_FUNCTION constexpr pair(const pair& p) + : first(p.first) {} template - KOKKOS_FORCEINLINE_FUNCTION - pair & operator=(const pair &p) - { + KOKKOS_FORCEINLINE_FUNCTION pair& operator=( + const pair& p) { first = p.first; return *this; } @@ -499,46 +470,52 @@ struct pair // template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator== (const pair& lhs, const pair& rhs) -{ return lhs.first==rhs.first; } +KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator==( + const pair& lhs, const pair& rhs) { + return lhs.first == rhs.first; +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator!= (const pair& lhs, const pair& rhs) -{ return !(lhs==rhs); } +KOKKOS_FORCEINLINE_FUNCTION constexpr bool operator!=( + const pair& lhs, const pair& rhs) { + return !(lhs == rhs); +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator< (const pair& lhs, const pair& rhs) -{ return lhs.first& lhs, const pair& rhs) { + return lhs.first < rhs.first; +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator<= (const pair& lhs, const pair& rhs) -{ return !(rhs& lhs, const pair& rhs) { + return !(rhs < lhs); +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator> (const pair& lhs, const pair& rhs) -{ return rhs( + const pair& lhs, const pair& rhs) { + return rhs < lhs; +} template -KOKKOS_FORCEINLINE_FUNCTION constexpr -bool operator>= (const pair& lhs, const pair& rhs) -{ return !(lhs=( + const pair& lhs, const pair& rhs) { + return !(lhs < rhs); +} namespace Impl { -template struct is_pair_like : std::false_type { }; -template struct is_pair_like> : std::true_type { }; -template struct is_pair_like> : std::true_type { }; - -} // end namespace Impl - -} // namespace Kokkos +template +struct is_pair_like : std::false_type {}; +template +struct is_pair_like> : std::true_type {}; +template +struct is_pair_like> : std::true_type {}; +} // end namespace Impl -#endif //KOKKOS_PAIR_HPP +} // namespace Kokkos +#endif // KOKKOS_PAIR_HPP diff --git a/lib/kokkos/core/src/Kokkos_Parallel.hpp b/lib/kokkos/core/src/Kokkos_Parallel.hpp index 09dcf60b11..7277ce287a 100644 --- a/lib/kokkos/core/src/Kokkos_Parallel.hpp +++ b/lib/kokkos/core/src/Kokkos_Parallel.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,7 +64,7 @@ #include #ifdef KOKKOS_DEBUG -#include +#include #endif //---------------------------------------------------------------------------- @@ -80,67 +81,52 @@ namespace Impl { * else if the Functor has a device_type use that for backward compatibility * else use the default */ -template< class Functor - , class Policy - , class EnableFunctor - , class EnablePolicy - > +template struct FunctorPolicyExecutionSpace { - typedef Kokkos::DefaultExecutionSpace execution_space ; + typedef Kokkos::DefaultExecutionSpace execution_space; }; -template< class Functor , class Policy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::device_type >::type - , typename enable_if_type< typename Policy ::execution_space >::type - > -{ - typedef typename Policy ::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + typename enable_if_type::type> { + typedef typename Policy ::execution_space execution_space; }; -template< class Functor , class Policy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::execution_space >::type - , typename enable_if_type< typename Policy ::execution_space >::type - > -{ - typedef typename Policy ::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + typename enable_if_type::type> { + typedef typename Policy ::execution_space execution_space; }; -template< class Functor , class Policy , class EnableFunctor > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , EnableFunctor - , typename enable_if_type< typename Policy::execution_space >::type - > -{ - typedef typename Policy ::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, EnableFunctor, + typename enable_if_type::type> { + typedef typename Policy ::execution_space execution_space; }; -template< class Functor , class Policy , class EnablePolicy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::device_type >::type - , EnablePolicy - > -{ - typedef typename Functor::device_type execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + EnablePolicy> { + typedef typename Functor::device_type execution_space; }; -template< class Functor , class Policy , class EnablePolicy > -struct FunctorPolicyExecutionSpace - < Functor , Policy - , typename enable_if_type< typename Functor::execution_space >::type - , EnablePolicy - > -{ - typedef typename Functor::execution_space execution_space ; +template +struct FunctorPolicyExecutionSpace< + Functor, Policy, + typename enable_if_type::type, + EnablePolicy> { + typedef typename Functor::execution_space execution_space; }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -168,89 +154,82 @@ namespace Kokkos { * This compares to a single iteration \c iwork of a \c for loop. * If \c execution_space is not defined DefaultExecutionSpace will be used. */ -template< class ExecPolicy , class FunctorType > -inline -void parallel_for( const ExecPolicy & policy - , const FunctorType & functor - , const std::string& str = "" - , typename Impl::enable_if< Kokkos::Impl::is_execution_policy< ExecPolicy >::value >::type * = 0 - ) -{ +template +inline void parallel_for( + const ExecPolicy& policy, const FunctorType& functor, + const std::string& str = "", + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(str); + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(str); Kokkos::Profiling::beginParallelFor(name.get(), 0, &kpID); } #endif - Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelFor< FunctorType , ExecPolicy > closure( functor , policy ); - Kokkos::Impl::shared_allocation_tracking_enable(); + Kokkos::Impl::shared_allocation_tracking_disable(); + Impl::ParallelFor closure(functor, policy); + Kokkos::Impl::shared_allocation_tracking_enable(); - closure.execute(); + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelFor(kpID); } #endif } -template< class FunctorType > -inline -void parallel_for( const size_t work_count - , const FunctorType & functor - , const std::string& str = "" - ) -{ - typedef typename - Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; - typedef RangePolicy< execution_space > policy ; +template +inline void parallel_for(const size_t work_count, const FunctorType& functor, + const std::string& str = "") { + typedef typename Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; + typedef RangePolicy policy; #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Impl::ParallelConstructName name(str); Kokkos::Profiling::beginParallelFor(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelFor< FunctorType , policy > closure( functor , policy(0,work_count) ); + Impl::ParallelFor closure(functor, + policy(0, work_count)); Kokkos::Impl::shared_allocation_tracking_enable(); closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelFor(kpID); - } + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelFor(kpID); + } #endif } -template< class ExecPolicy , class FunctorType > -inline -void parallel_for( const std::string & str - , const ExecPolicy & policy - , const FunctorType & functor ) -{ - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +template +inline void parallel_for(const std::string& str, const ExecPolicy& policy, + const FunctorType& functor) { +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG Start parallel_for kernel: " << str << std::endl; - #endif +#endif - ::Kokkos::parallel_for(policy,functor,str); + ::Kokkos::parallel_for(policy, functor, str); - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG End parallel_for kernel: " << str << std::endl; - #endif - (void) str; +#endif + (void)str; } -} +} // namespace Kokkos #include //---------------------------------------------------------------------------- @@ -291,9 +270,9 @@ namespace Kokkos { /// // operator() or join(). /// typedef PodType value_type; /// -/// void operator () (const ExecPolicy::member_type & i, value_type& update, const bool final_pass) const; -/// void init (value_type& update) const; -/// void join (volatile value_type& update, volatile const value_type& input) const +/// void operator () (const ExecPolicy::member_type & i, value_type& update, +/// const bool final_pass) const; void init (value_type& update) const; void +/// join (volatile value_type& update, volatile const value_type& input) const /// }; /// \endcode /// @@ -310,9 +289,11 @@ namespace Kokkos { /// typedef typename SpaceType::size_type size_type; /// /// InclScanFunctor( Kokkos::View x -/// , Kokkos::View y ) : m_x(x), m_y(y) {} +/// , Kokkos::View y ) : m_x(x), +/// m_y(y) {} /// -/// void operator () (const size_type i, value_type& update, const bool final_pass) const { +/// void operator () (const size_type i, value_type& update, const bool +/// final_pass) const { /// update += m_x(i); /// if (final_pass) { /// m_y(i) = update; @@ -321,7 +302,8 @@ namespace Kokkos { /// void init (value_type& update) const { /// update = 0; /// } -/// void join (volatile value_type& update, volatile const value_type& input) const { +/// void join (volatile value_type& update, volatile const value_type& input) +/// const { /// update += input; /// } /// @@ -347,7 +329,8 @@ namespace Kokkos { /// /// ExclScanFunctor (Kokkos::View x) : x_ (x) {} /// -/// void operator () (const size_type i, value_type& update, const bool final_pass) const { +/// void operator () (const size_type i, value_type& update, const bool +/// final_pass) const { /// const value_type x_i = x_(i); /// if (final_pass) { /// x_(i) = update; @@ -357,7 +340,8 @@ namespace Kokkos { /// void init (value_type& update) const { /// update = 0; /// } -/// void join (volatile value_type& update, volatile const value_type& input) const { +/// void join (volatile value_type& update, volatile const value_type& input) +/// const { /// update += input; /// } /// @@ -385,10 +369,12 @@ namespace Kokkos { /// // If x has length zero, then lastIndex_ won't be used anyway. /// OffsetScanFunctor( Kokkos::View x /// , Kokkos::View y ) -/// : m_x(x), m_y(y), last_index_ (x.dimension_0 () == 0 ? 0 : x.dimension_0 () - 1) +/// : m_x(x), m_y(y), last_index_ (x.dimension_0 () == 0 ? 0 : +/// x.dimension_0 () - 1) /// {} /// -/// void operator () (const size_type i, int& update, const bool final_pass) const { +/// void operator () (const size_type i, int& update, const bool final_pass) +/// const { /// if (final_pass) { /// m_y(i) = update; /// } @@ -396,12 +382,13 @@ namespace Kokkos { /// // The last entry of m_y gets the final sum. /// if (final_pass && i == last_index_) { /// m_y(i+1) = update; -//i/ } +// i/ } /// } /// void init (value_type& update) const { /// update = 0; /// } -/// void join (volatile value_type& update, volatile const value_type& input) const { +/// void join (volatile value_type& update, volatile const value_type& input) +/// const { /// update += input; /// } /// @@ -412,181 +399,164 @@ namespace Kokkos { /// }; /// \endcode /// -template< class ExecutionPolicy , class FunctorType > -inline -void parallel_scan( const ExecutionPolicy & policy - , const FunctorType & functor - , const std::string& str = "" - , typename Impl::enable_if< Kokkos::Impl::is_execution_policy< ExecutionPolicy >::value >::type * = 0 - ) -{ +template +inline void parallel_scan( + const ExecutionPolicy& policy, const FunctorType& functor, + const std::string& str = "", + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(str); + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScan< FunctorType , ExecutionPolicy > closure( functor , policy ); + Impl::ParallelScan closure(functor, policy); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif - } -template< class FunctorType > -inline -void parallel_scan( const size_t work_count - , const FunctorType & functor - , const std::string& str = "" ) -{ - typedef typename - Kokkos::Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; +template +inline void parallel_scan(const size_t work_count, const FunctorType& functor, + const std::string& str = "") { + typedef typename Kokkos::Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; - typedef Kokkos::RangePolicy< execution_space > policy ; + typedef Kokkos::RangePolicy policy; #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Impl::ParallelConstructName name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScan< FunctorType , policy > closure( functor , policy(0,work_count) ); + Impl::ParallelScan closure(functor, + policy(0, work_count)); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif - } -template< class ExecutionPolicy , class FunctorType > -inline -void parallel_scan( const std::string& str - , const ExecutionPolicy & policy - , const FunctorType & functor) -{ - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +template +inline void parallel_scan(const std::string& str, const ExecutionPolicy& policy, + const FunctorType& functor) { +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG Start parallel_scan kernel: " << str << std::endl; - #endif - - ::Kokkos::parallel_scan(policy,functor,str); +#endif + + ::Kokkos::parallel_scan(policy, functor, str); - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG End parallel_scan kernel: " << str << std::endl; - #endif - (void) str; +#endif + (void)str; } - -template< class ExecutionPolicy , class FunctorType, class ReturnType > -inline -void parallel_scan( const ExecutionPolicy & policy - , const FunctorType & functor - , ReturnType & return_value - , const std::string& str = "" - , typename Impl::enable_if< Kokkos::Impl::is_execution_policy< ExecutionPolicy >::value >::type * = 0 - ) -{ +template +inline void parallel_scan( + const ExecutionPolicy& policy, const FunctorType& functor, + ReturnType& return_value, const std::string& str = "", + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(str); + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScanWithTotal< FunctorType , ExecutionPolicy, ReturnType > closure( functor, policy, return_value ); + Impl::ParallelScanWithTotal closure( + functor, policy, return_value); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif Kokkos::fence(); } -template< class FunctorType, class ReturnType > -inline -void parallel_scan( const size_t work_count - , const FunctorType & functor - , ReturnType & return_value - , const std::string & str = "" ) -{ - typedef typename - Kokkos::Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; +template +inline void parallel_scan(const size_t work_count, const FunctorType& functor, + ReturnType& return_value, + const std::string& str = "") { + typedef typename Kokkos::Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; - typedef Kokkos::RangePolicy< execution_space > policy ; + typedef Kokkos::RangePolicy policy; #if defined(KOKKOS_ENABLE_PROFILING) uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Impl::ParallelConstructName name(str); Kokkos::Profiling::beginParallelScan(name.get(), 0, &kpID); } #endif Kokkos::Impl::shared_allocation_tracking_disable(); - Impl::ParallelScanWithTotal< FunctorType, policy, ReturnType > closure( functor, policy(0,work_count), return_value ); + Impl::ParallelScanWithTotal closure( + functor, policy(0, work_count), return_value); Kokkos::Impl::shared_allocation_tracking_enable(); - + closure.execute(); #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { + if (Kokkos::Profiling::profileLibraryLoaded()) { Kokkos::Profiling::endParallelScan(kpID); } #endif Kokkos::fence(); } -template< class ExecutionPolicy, class FunctorType, class ReturnType > -inline -void parallel_scan( const std::string& str - , const ExecutionPolicy & policy - , const FunctorType & functor - , ReturnType & return_value) -{ - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +template +inline void parallel_scan(const std::string& str, const ExecutionPolicy& policy, + const FunctorType& functor, + ReturnType& return_value) { +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG Start parallel_scan kernel: " << str << std::endl; - #endif - - ::Kokkos::parallel_scan(policy,functor,return_value,str); +#endif + + ::Kokkos::parallel_scan(policy, functor, return_value, str); - #if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES +#if KOKKOS_ENABLE_DEBUG_PRINT_KERNEL_NAMES Kokkos::fence(); std::cout << "KOKKOS_DEBUG End parallel_scan kernel: " << str << std::endl; - #endif - (void) str; +#endif + (void)str; } - - -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -594,29 +564,35 @@ void parallel_scan( const std::string& str namespace Kokkos { namespace Impl { -template< class FunctorType , class Enable = void > -struct FunctorTeamShmemSize -{ - KOKKOS_INLINE_FUNCTION static size_t value( const FunctorType & , int ) { return 0 ; } +template +struct FunctorTeamShmemSize { + KOKKOS_INLINE_FUNCTION static size_t value(const FunctorType&, int) { + return 0; + } }; -template< class FunctorType > -struct FunctorTeamShmemSize< FunctorType , typename Impl::enable_if< 0 < sizeof( & FunctorType::team_shmem_size ) >::type > -{ - static inline size_t value( const FunctorType & f , int team_size ) { return f.team_shmem_size( team_size ) ; } +template +struct FunctorTeamShmemSize< + FunctorType, + typename Impl::enable_if<0 < sizeof(&FunctorType::team_shmem_size)>::type> { + static inline size_t value(const FunctorType& f, int team_size) { + return f.team_shmem_size(team_size); + } }; -template< class FunctorType > -struct FunctorTeamShmemSize< FunctorType , typename Impl::enable_if< 0 < sizeof( & FunctorType::shmem_size ) >::type > -{ - static inline size_t value( const FunctorType & f , int team_size ) { return f.shmem_size( team_size ) ; } +template +struct FunctorTeamShmemSize< + FunctorType, + typename Impl::enable_if<0 < sizeof(&FunctorType::shmem_size)>::type> { + static inline size_t value(const FunctorType& f, int team_size) { + return f.shmem_size(team_size); + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* KOKKOS_PARALLEL_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp b/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp index 0e02c468e4..1fa23f714f 100644 --- a/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp +++ b/lib/kokkos/core/src/Kokkos_Parallel_Reduce.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,46 +49,43 @@ namespace Kokkos { -template +template struct is_reducer_type { enum { value = 0 }; }; - -template -struct is_reducer_type::type, - typename std::remove_cv::type>::value - >::type> { +template +struct is_reducer_type< + T, typename std::enable_if::type, + typename std::remove_cv::type>::value>::type> { enum { value = 1 }; }; -template +template struct Sum { -public: - //Required + public: + // Required typedef Sum reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Sum(value_type& value_): value(&value_),references_scalar_v(true) {} + Sum(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Sum(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Sum(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest += src; - } + void join(value_type& dest, const value_type& src) const { dest += src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { @@ -95,52 +93,44 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::sum(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct Prod { -public: - //Required + public: + // Required typedef Prod reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Prod(value_type& value_): value(&value_),references_scalar_v(true) {} + Prod(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Prod(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Prod(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest *= src; - } + void join(value_type& dest, const value_type& src) const { dest *= src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { @@ -148,160 +138,138 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::prod(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct Min { -public: - //Required + public: + // Required typedef Min reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Min(value_type& value_): value(&value_),references_scalar_v(true) {} + Min(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Min(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Min(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src < dest ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src < dest) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src < dest ) - dest = src; + if (src < dest) dest = src; } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct Max { -public: - //Required + public: + // Required typedef Max reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - Max(value_type& value_): value(&value_),references_scalar_v(true) {} + Max(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - Max(const result_view_type& value_): value(value_),references_scalar_v(false) {} + Max(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src > dest ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src > dest) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src > dest ) - dest = src; + if (src > dest) dest = src; } - //Required + // Required KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::max(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct LAnd { -public: - //Required + public: + // Required typedef LAnd reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - LAnd(value_type& value_): value(&value_),references_scalar_v(true) {} + LAnd(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - LAnd(const result_view_type& value_): value(value_),references_scalar_v(false) {} + LAnd(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { + void join(value_type& dest, const value_type& src) const { dest = dest && src; } @@ -311,50 +279,44 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::land(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct LOr { -public: - //Required + public: + // Required typedef LOr reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - LOr(value_type& value_): value(&value_),references_scalar_v(true) {} + LOr(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - LOr(const result_view_type& value_): value(value_),references_scalar_v(false) {} + LOr(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { + void join(value_type& dest, const value_type& src) const { dest = dest || src; } @@ -364,51 +326,45 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::lor(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct BAnd { -public: - //Required + public: + // Required typedef BAnd reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - BAnd(value_type& value_): value(&value_),references_scalar_v(true) {} + BAnd(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - BAnd(const result_view_type& value_): value(value_),references_scalar_v(false) {} + BAnd(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest = dest & src; + void join(value_type& dest, const value_type& src) const { + dest = dest & src; } KOKKOS_INLINE_FUNCTION @@ -417,51 +373,45 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::band(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct BOr { -public: - //Required + public: + // Required typedef BOr reducer; typedef typename std::remove_cv::type value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - BOr(value_type& value_): value(&value_),references_scalar_v(true) {} + BOr(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - BOr(const result_view_type& value_): value(value_),references_scalar_v(false) {} + BOr(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - dest = dest | src; + void join(value_type& dest, const value_type& src) const { + dest = dest | src; } KOKKOS_INLINE_FUNCTION @@ -470,256 +420,229 @@ public: } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val = reduction_identity::bor(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct ValLocScalar { Scalar val; Index loc; KOKKOS_INLINE_FUNCTION - void operator = (const ValLocScalar& rhs) { + void operator=(const ValLocScalar& rhs) { val = rhs.val; loc = rhs.loc; } KOKKOS_INLINE_FUNCTION - void operator = (const volatile ValLocScalar& rhs) volatile { + void operator=(const volatile ValLocScalar& rhs) volatile { val = rhs.val; loc = rhs.loc; } }; -template +template struct MinLoc { -private: + private: typedef typename std::remove_cv::type scalar_type; typedef typename std::remove_cv::type index_type; -public: - //Required + public: + // Required typedef MinLoc reducer; - typedef ValLocScalar value_type; + typedef ValLocScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MinLoc(value_type& value_): value(&value_),references_scalar_v(true) {} + MinLoc(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MinLoc(const result_view_type& value_): value(value_),references_scalar_v(false) {} - + MinLoc(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.val < dest.val ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src.val < dest.val) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.val < dest.val ) - dest = src; + if (src.val < dest.val) dest = src; } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { + void init(value_type& val) const { val.val = reduction_identity::min(); val.loc = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct MaxLoc { -private: + private: typedef typename std::remove_cv::type scalar_type; typedef typename std::remove_cv::type index_type; -public: - //Required + public: + // Required typedef MaxLoc reducer; - typedef ValLocScalar value_type; + typedef ValLocScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MaxLoc(value_type& value_): value(&value_),references_scalar_v(true) {} + MaxLoc(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MaxLoc(const result_view_type& value_): value(value_),references_scalar_v(false) {} + MaxLoc(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.val > dest.val ) - dest = src; + void join(value_type& dest, const value_type& src) const { + if (src.val > dest.val) dest = src; } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.val > dest.val ) - dest = src; + if (src.val > dest.val) dest = src; } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { - val.val = reduction_identity::max();; + void init(value_type& val) const { + val.val = reduction_identity::max(); + ; val.loc = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct MinMaxScalar { - Scalar min_val,max_val; + Scalar min_val, max_val; KOKKOS_INLINE_FUNCTION - void operator = (const MinMaxScalar& rhs) { + void operator=(const MinMaxScalar& rhs) { min_val = rhs.min_val; max_val = rhs.max_val; } KOKKOS_INLINE_FUNCTION - void operator = (const volatile MinMaxScalar& rhs) volatile { + void operator=(const volatile MinMaxScalar& rhs) volatile { min_val = rhs.min_val; max_val = rhs.max_val; } }; -template +template struct MinMax { -private: + private: typedef typename std::remove_cv::type scalar_type; -public: - //Required + public: + // Required typedef MinMax reducer; typedef MinMaxScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MinMax(value_type& value_): value(&value_),references_scalar_v(true) {} + MinMax(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MinMax(const result_view_type& value_): value(value_),references_scalar_v(false) {} + MinMax(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.min_val < dest.min_val ) { + void join(value_type& dest, const value_type& src) const { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; } } KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.min_val < dest.min_val ) { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; } } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { - val.max_val = reduction_identity::max();; + void init(value_type& val) const { + val.max_val = reduction_identity::max(); + ; val.min_val = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -template +template struct MinMaxLocScalar { - Scalar min_val,max_val; - Index min_loc,max_loc; + Scalar min_val, max_val; + Index min_loc, max_loc; KOKKOS_INLINE_FUNCTION - void operator = (const MinMaxLocScalar& rhs) { + void operator=(const MinMaxLocScalar& rhs) { min_val = rhs.min_val; min_loc = rhs.min_loc; max_val = rhs.max_val; @@ -727,7 +650,7 @@ struct MinMaxLocScalar { } KOKKOS_INLINE_FUNCTION - void operator = (const volatile MinMaxLocScalar& rhs) volatile { + void operator=(const volatile MinMaxLocScalar& rhs) volatile { min_val = rhs.min_val; min_loc = rhs.min_loc; max_val = rhs.max_val; @@ -735,39 +658,39 @@ struct MinMaxLocScalar { } }; -template +template struct MinMaxLoc { -private: + private: typedef typename std::remove_cv::type scalar_type; typedef typename std::remove_cv::type index_type; -public: - //Required + public: + // Required typedef MinMaxLoc reducer; - typedef MinMaxLocScalar value_type; + typedef MinMaxLocScalar value_type; typedef Kokkos::View result_view_type; -private: + private: result_view_type value; bool references_scalar_v; -public: - + public: KOKKOS_INLINE_FUNCTION - MinMaxLoc(value_type& value_): value(&value_),references_scalar_v(true) {} + MinMaxLoc(value_type& value_) : value(&value_), references_scalar_v(true) {} KOKKOS_INLINE_FUNCTION - MinMaxLoc(const result_view_type& value_): value(value_),references_scalar_v(false) {} + MinMaxLoc(const result_view_type& value_) + : value(value_), references_scalar_v(false) {} - //Required + // Required KOKKOS_INLINE_FUNCTION - void join(value_type& dest, const value_type& src) const { - if ( src.min_val < dest.min_val ) { + void join(value_type& dest, const value_type& src) const { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; dest.min_loc = src.min_loc; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; dest.max_loc = src.max_loc; } @@ -775,71 +698,68 @@ public: KOKKOS_INLINE_FUNCTION void join(volatile value_type& dest, const volatile value_type& src) const { - if ( src.min_val < dest.min_val ) { + if (src.min_val < dest.min_val) { dest.min_val = src.min_val; dest.min_loc = src.min_loc; } - if ( src.max_val > dest.max_val ) { + if (src.max_val > dest.max_val) { dest.max_val = src.max_val; dest.max_loc = src.max_loc; } } KOKKOS_INLINE_FUNCTION - void init( value_type& val) const { - val.max_val = reduction_identity::max();; + void init(value_type& val) const { + val.max_val = reduction_identity::max(); + ; val.min_val = reduction_identity::min(); val.max_loc = reduction_identity::min(); val.min_loc = reduction_identity::min(); } KOKKOS_INLINE_FUNCTION - value_type& reference() const { - return *value.data(); - } + value_type& reference() const { return *value.data(); } KOKKOS_INLINE_FUNCTION - result_view_type view() const { - return value; - } + result_view_type view() const { return value; } KOKKOS_INLINE_FUNCTION - bool references_scalar() const { - return references_scalar_v; - } + bool references_scalar() const { return references_scalar_v; } }; -} -namespace Kokkos{ +} // namespace Kokkos +namespace Kokkos { namespace Impl { -template< class T, class ReturnType , class ValueTraits> +template struct ParallelReduceReturnValue; -template< class ReturnType , class FunctorType > -struct ParallelReduceReturnValue::value>::type, ReturnType, FunctorType> { +template +struct ParallelReduceReturnValue< + typename std::enable_if::value>::type, + ReturnType, FunctorType> { typedef ReturnType return_type; typedef InvalidType reducer_type; typedef typename return_type::value_type value_type_scalar; typedef typename return_type::value_type* const value_type_array; - typedef typename if_c::type value_type; + typedef typename if_c::type value_type; static return_type& return_value(ReturnType& return_val, const FunctorType&) { return return_val; } }; -template< class ReturnType , class FunctorType> -struct ParallelReduceReturnValue::value && - (!std::is_array::value && !std::is_pointer::value) && - !Kokkos::is_reducer_type::value - >::type, ReturnType, FunctorType> { - typedef Kokkos::View< ReturnType - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > return_type; +template +struct ParallelReduceReturnValue< + typename std::enable_if::value && + (!std::is_array::value && + !std::is_pointer::value) && + !Kokkos::is_reducer_type::value>::type, + ReturnType, FunctorType> { + typedef Kokkos::View + return_type; typedef InvalidType reducer_type; @@ -850,14 +770,14 @@ struct ParallelReduceReturnValue -struct ParallelReduceReturnValue::value || std::is_pointer::value) - >::type, ReturnType, FunctorType> { - typedef Kokkos::View< typename std::remove_const::type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > return_type; +template +struct ParallelReduceReturnValue< + typename std::enable_if<(is_array::value || + std::is_pointer::value)>::type, + ReturnType, FunctorType> { + typedef Kokkos::View::type, + Kokkos::HostSpace, Kokkos::MemoryUnmanaged> + return_type; typedef InvalidType reducer_type; @@ -866,150 +786,154 @@ struct ParallelReduceReturnValue::value ) + if (is_array::value) return return_type(return_val); else - return return_type(return_val,functor.value_count); + return return_type(return_val, functor.value_count); #endif } }; -template< class ReturnType , class FunctorType> -struct ParallelReduceReturnValue::value - >::type, ReturnType, FunctorType> { +template +struct ParallelReduceReturnValue< + typename std::enable_if::value>::type, + ReturnType, FunctorType> { typedef ReturnType return_type; typedef ReturnType reducer_type; typedef typename return_type::value_type value_type; - static return_type return_value(ReturnType& return_val, - const FunctorType&) { + static return_type return_value(ReturnType& return_val, const FunctorType&) { return return_val; } }; -template< class T, class ReturnType , class FunctorType> +template struct ParallelReducePolicyType; -template< class PolicyType , class FunctorType > -struct ParallelReducePolicyType::value>::type, PolicyType,FunctorType> { - +template +struct ParallelReducePolicyType< + typename std::enable_if< + Kokkos::Impl::is_execution_policy::value>::type, + PolicyType, FunctorType> { typedef PolicyType policy_type; - static PolicyType policy(const PolicyType& policy_) { - return policy_; - } + static PolicyType policy(const PolicyType& policy_) { return policy_; } }; -template< class PolicyType , class FunctorType > -struct ParallelReducePolicyType::value>::type, PolicyType,FunctorType> { - typedef typename - Impl::FunctorPolicyExecutionSpace< FunctorType , void >::execution_space - execution_space ; +template +struct ParallelReducePolicyType< + typename std::enable_if::value>::type, + PolicyType, FunctorType> { + typedef typename Impl::FunctorPolicyExecutionSpace< + FunctorType, void>::execution_space execution_space; typedef Kokkos::RangePolicy policy_type; static policy_type policy(const PolicyType& policy_) { - return policy_type(0,policy_); + return policy_type(0, policy_); } }; +template +struct ParallelReduceFunctorType { + typedef FunctorType functor_type; + static const functor_type& functor(const functor_type& functor) { + return functor; + } +}; - template< class FunctorType, class ExecPolicy, class ValueType, class ExecutionSpace> - struct ParallelReduceFunctorType { - typedef FunctorType functor_type; - static const functor_type& functor(const functor_type& functor) { - return functor; +template +struct ParallelReduceAdaptor { + typedef Impl::ParallelReduceReturnValue + return_value_adapter; +#ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER + typedef Impl::ParallelReduceFunctorType< + FunctorType, PolicyType, typename return_value_adapter::value_type, + typename PolicyType::execution_space> + functor_adaptor; +#endif + static inline void execute(const std::string& label, const PolicyType& policy, + const FunctorType& functor, + ReturnType& return_value) { +#if defined(KOKKOS_ENABLE_PROFILING) + uint64_t kpID = 0; + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Impl::ParallelConstructName + name(label); + Kokkos::Profiling::beginParallelReduce(name.get(), 0, &kpID); } - }; +#endif - template< class PolicyType, class FunctorType, class ReturnType > - struct ParallelReduceAdaptor { - typedef Impl::ParallelReduceReturnValue return_value_adapter; - #ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER - typedef Impl::ParallelReduceFunctorType functor_adaptor; - #endif - static inline - void execute(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - ReturnType& return_value) { - #if defined(KOKKOS_ENABLE_PROFILING) - uint64_t kpID = 0; - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Impl::ParallelConstructName name(label); - Kokkos::Profiling::beginParallelReduce(name.get(), 0, &kpID); - } - #endif - - Kokkos::Impl::shared_allocation_tracking_disable(); - #ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER - Impl::ParallelReduce - closure(functor_adaptor::functor(functor), - policy, - return_value_adapter::return_value(return_value,functor)); - #else - Impl::ParallelReduce - closure(functor, - policy, - return_value_adapter::return_value(return_value,functor)); - #endif - Kokkos::Impl::shared_allocation_tracking_enable(); - closure.execute(); - - #if defined(KOKKOS_ENABLE_PROFILING) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::endParallelReduce(kpID); - } - #endif - } + Kokkos::Impl::shared_allocation_tracking_disable(); +#ifdef KOKKOS_IMPL_NEED_FUNCTOR_WRAPPER + Impl::ParallelReduce + closure(functor_adaptor::functor(functor), policy, + return_value_adapter::return_value(return_value, functor)); +#else + Impl::ParallelReduce + closure(functor, policy, + return_value_adapter::return_value(return_value, functor)); +#endif + Kokkos::Impl::shared_allocation_tracking_enable(); + closure.execute(); - }; -} +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::endParallelReduce(kpID); + } +#endif + } +}; +} // namespace Impl //---------------------------------------------------------------------------- /*! \fn void parallel_reduce(label,policy,functor,return_argument) \brief Perform a parallel reduction. - \param label An optional Label giving the call name. Must be able to construct a std::string from the argument. - \param policy A Kokkos Execution Policy, such as an integer, a RangePolicy or a TeamPolicy. - \param functor A functor with a reduction operator, and optional init, join and final functions. - \param return_argument A return argument which can be a scalar, a View, or a ReducerStruct. This argument can be left out if the functor has a final function. + \param label An optional Label giving the call name. Must be able to + construct a std::string from the argument. \param policy A Kokkos Execution + Policy, such as an integer, a RangePolicy or a TeamPolicy. \param functor A + functor with a reduction operator, and optional init, join and final + functions. \param return_argument A return argument which can be a scalar, a + View, or a ReducerStruct. This argument can be left out if the functor has a + final function. */ // Parallel Reduce Blocking behavior namespace Impl { template - struct ReducerHasTestReferenceFunction - { - template static std::true_type test_func( decltype(&E::references_scalar) ) ; - template static std::false_type test_func(...); - - enum { value = std::is_same(0))>::value }; +struct ReducerHasTestReferenceFunction { + template + static std::true_type test_func(decltype(&E::references_scalar)); + template + static std::false_type test_func(...); + + enum { + value = std::is_same(0))>::value }; +}; - template::value> - struct ParallelReduceFence { - static void fence(const T&) { - Kokkos::fence(); - } - }; - template - struct ParallelReduceFence, false> { - static void fence(const View) {}; - }; - template - struct ParallelReduceFence { - static void fence(const T& reducer) { - if(reducer.references_scalar()) - Kokkos::fence(); - } - }; -} +template ::value> +struct ParallelReduceFence { + static void fence(const T&) { Kokkos::fence(); } +}; +template +struct ParallelReduceFence, false> { + static void fence(const View){}; +}; +template +struct ParallelReduceFence { + static void fence(const T& reducer) { + if (reducer.references_scalar()) Kokkos::fence(); + } +}; +} // namespace Impl /** \brief Parallel reduction * @@ -1033,16 +957,12 @@ template * }; * \endcode * - * Example of a parallel_reduce functor for an array of POD (plain old data) values: - * \code - * class FunctorType { // For array of POD value - * public: - * typedef ... execution_space ; - * typedef value_type[] ; - * void operator()( , update[] ) const ; - * void init( update[] ) const ; - * void join( volatile update[] , - * volatile const input[] ) const ; + * Example of a parallel_reduce functor for an array of POD (plain old data) + * values: \code class FunctorType { // For array of POD value public: typedef + * ... execution_space ; typedef value_type[] ; void operator()( + * , update[] ) const ; void init( update[] ) + * const ; void join( volatile update[] , volatile const + * input[] ) const ; * * typedef true_type has_final ; * void final( update[] ) const ; @@ -1052,226 +972,223 @@ template // ReturnValue is scalar or array: take by reference -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - Impl::ParallelReduceAdaptor::execute(label,policy,functor,return_value); +template +inline void parallel_reduce( + const std::string& label, const PolicyType& policy, + const FunctorType& functor, ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + Impl::ParallelReduceAdaptor::execute( + label, policy, functor, return_value); Impl::ParallelReduceFence::fence(return_value); } -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const PolicyType& policy, - const FunctorType& functor, - ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - Impl::ParallelReduceAdaptor::execute("",policy,functor,return_value); +template +inline void parallel_reduce( + const PolicyType& policy, const FunctorType& functor, + ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + Impl::ParallelReduceAdaptor::execute( + "", policy, functor, return_value); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const size_t& policy, - const FunctorType& functor, - ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - Impl::ParallelReduceAdaptor::execute("",policy_type(0,policy),functor,return_value); +template +inline void parallel_reduce(const size_t& policy, const FunctorType& functor, + ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + Impl::ParallelReduceAdaptor::execute( + "", policy_type(0, policy), functor, return_value); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const size_t& policy, - const FunctorType& functor, - ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - Impl::ParallelReduceAdaptor::execute(label,policy_type(0,policy),functor,return_value); +template +inline void parallel_reduce(const std::string& label, const size_t& policy, + const FunctorType& functor, + ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + Impl::ParallelReduceAdaptor::execute( + label, policy_type(0, policy), functor, return_value); Impl::ParallelReduceFence::fence(return_value); } // ReturnValue as View or Reducer: take by copy to allow for inline construction -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - const ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { +template +inline void parallel_reduce( + const std::string& label, const PolicyType& policy, + const FunctorType& functor, const ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute(label,policy,functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + label, policy, functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } -template< class PolicyType, class FunctorType, class ReturnType > -inline -void parallel_reduce(const PolicyType& policy, - const FunctorType& functor, - const ReturnType& return_value, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { +template +inline void parallel_reduce( + const PolicyType& policy, const FunctorType& functor, + const ReturnType& return_value, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute("",policy,functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + "", policy, functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const size_t& policy, - const FunctorType& functor, - const ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; +template +inline void parallel_reduce(const size_t& policy, const FunctorType& functor, + const ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute("",policy_type(0,policy),functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + "", policy_type(0, policy), functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } -template< class FunctorType, class ReturnType > -inline -void parallel_reduce(const std::string& label, - const size_t& policy, - const FunctorType& functor, - const ReturnType& return_value) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; +template +inline void parallel_reduce(const std::string& label, const size_t& policy, + const FunctorType& functor, + const ReturnType& return_value) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; ReturnType return_value_impl = return_value; - Impl::ParallelReduceAdaptor::execute(label,policy_type(0,policy),functor,return_value_impl); + Impl::ParallelReduceAdaptor::execute( + label, policy_type(0, policy), functor, return_value_impl); Impl::ParallelReduceFence::fence(return_value); } // No Return Argument -template< class PolicyType, class FunctorType> -inline -void parallel_reduce(const std::string& label, - const PolicyType& policy, - const FunctorType& functor, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute(label,policy,functor,result_view); +template +inline void parallel_reduce( + const std::string& label, const PolicyType& policy, + const FunctorType& functor, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute(label, policy, functor, + result_view); } -template< class PolicyType, class FunctorType > -inline -void parallel_reduce(const PolicyType& policy, - const FunctorType& functor, - typename Impl::enable_if< - Kokkos::Impl::is_execution_policy::value - >::type * = 0) { - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute("",policy,functor,result_view); +template +inline void parallel_reduce( + const PolicyType& policy, const FunctorType& functor, + typename Impl::enable_if< + Kokkos::Impl::is_execution_policy::value>::type* = 0) { + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute("", policy, functor, + result_view); } -template< class FunctorType > -inline -void parallel_reduce(const size_t& policy, - const FunctorType& functor) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis,FunctorType>:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute("",policy_type(0,policy),functor,result_view); +template +inline void parallel_reduce(const size_t& policy, const FunctorType& functor) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis, + FunctorType>::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute("", + policy_type(0, policy), + functor, result_view); } -template< class FunctorType> -inline -void parallel_reduce(const std::string& label, - const size_t& policy, - const FunctorType& functor) { - typedef typename Impl::ParallelReducePolicyType::policy_type policy_type; - typedef Kokkos::Impl::FunctorValueTraits< FunctorType , void > ValueTraits ; - typedef typename Kokkos::Impl::if_c< (ValueTraits::StaticValueSize != 0) - , typename ValueTraits::value_type - , typename ValueTraits::pointer_type - >::type value_type ; - - static_assert(Impl::FunctorAnalysis,FunctorType>:: - has_final_member_function,"Calling parallel_reduce without either return value or final function."); - - typedef Kokkos::View< value_type - , Kokkos::HostSpace - , Kokkos::MemoryUnmanaged - > result_view_type; - result_view_type result_view ; - - Impl::ParallelReduceAdaptor::execute(label,policy_type(0,policy),functor,result_view); +template +inline void parallel_reduce(const std::string& label, const size_t& policy, + const FunctorType& functor) { + typedef typename Impl::ParallelReducePolicyType< + void, size_t, FunctorType>::policy_type policy_type; + typedef Kokkos::Impl::FunctorValueTraits ValueTraits; + typedef typename Kokkos::Impl::if_c< + (ValueTraits::StaticValueSize != 0), typename ValueTraits::value_type, + typename ValueTraits::pointer_type>::type value_type; + + static_assert( + Impl::FunctorAnalysis, + FunctorType>::has_final_member_function, + "Calling parallel_reduce without either return value or final function."); + + typedef Kokkos::View + result_view_type; + result_view_type result_view; + + Impl::ParallelReduceAdaptor::execute(label, + policy_type(0, policy), + functor, result_view); } -} //namespace Kokkos +} // namespace Kokkos #ifdef KOKKOS_ENABLE_DEPRECATED_CODE -//backwards compatibility for Kokkos::Experimental reducers -namespace Kokkos { namespace Experimental { -using Kokkos::Sum; -using Kokkos::Prod; -using Kokkos::Min; -using Kokkos::Max; -using Kokkos::LAnd; -using Kokkos::LOr; +// backwards compatiblity for Kokkos::Experimental reducers +namespace Kokkos { +namespace Experimental { using Kokkos::BAnd; using Kokkos::BOr; -using Kokkos::ValLocScalar; -using Kokkos::MinLoc; +using Kokkos::LAnd; +using Kokkos::LOr; +using Kokkos::Max; using Kokkos::MaxLoc; -using Kokkos::MinMaxScalar; +using Kokkos::Min; +using Kokkos::MinLoc; using Kokkos::MinMax; -using Kokkos::MinMaxLocScalar; using Kokkos::MinMaxLoc; -}} //namespace Kokkos::Experimental +using Kokkos::MinMaxLocScalar; +using Kokkos::MinMaxScalar; +using Kokkos::Prod; +using Kokkos::Sum; +using Kokkos::ValLocScalar; +} // namespace Experimental +} // namespace Kokkos #endif -#endif // KOKKOS_PARALLEL_REDUCE_HPP - +#endif // KOKKOS_PARALLEL_REDUCE_HPP diff --git a/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp b/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp index be76ec3def..f1f168c38f 100644 --- a/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp +++ b/lib/kokkos/core/src/Kokkos_PointerOwnership.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -63,12 +64,9 @@ using OwningRawPtr = T*; template using ObservingRawPtr = T*; -} // end namespace Kokkos +} // end namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- - - #endif /* #ifndef KOKKOS_IMPL_POINTEROWNERSHIP_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp b/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp index b3fd3af70b..3c667f4432 100644 --- a/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp +++ b/lib/kokkos/core/src/Kokkos_Profiling_ProfileSection.hpp @@ -1,45 +1,46 @@ /* - //@HEADER - // ************************************************************************ - // - // Kokkos v. 2.0 - // Copyright (2014) Sandia Corporation - // - // Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, - // the U.S. Government retains certain rights in this software. - // - // Redistribution and use in source and binary forms, with or without - // modification, are permitted provided that the following conditions are - // met: - // - // 1. Redistributions of source code must retain the above copyright - // notice, this list of conditions and the following disclaimer. - // - // 2. Redistributions in binary form must reproduce the above copyright - // notice, this list of conditions and the following disclaimer in the - // documentation and/or other materials provided with the distribution. - // - // 3. Neither the name of the Corporation nor the names of the - // contributors may be used to endorse or promote products derived from - // this software without specific prior written permission. - // - // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY - // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE - // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - // - // Questions? Contact Christian R. Trott (crtrott@sandia.gov) - // - // ************************************************************************ - //@HEADER - */ +//@HEADER +// ************************************************************************ +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, +// the U.S. Government retains certain rights in this software. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// 1. Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// 2. Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// 3. Neither the name of the Corporation nor the names of the +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +// Questions? Contact Christian R. Trott (crtrott@sandia.gov) +// +// ************************************************************************ +//@HEADER +*/ #ifndef KOKKOSP_PROFILE_SECTION_HPP #define KOKKOSP_PROFILE_SECTION_HPP @@ -53,59 +54,51 @@ namespace Kokkos { namespace Profiling { class ProfilingSection { + public: + ProfilingSection(const std::string& sectionName) : secName(sectionName) { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::createProfileSection(secName, &secID); + } +#else + secID = 0; +#endif + } -public: - ProfilingSection(const std::string& sectionName) : - secName(sectionName) { + void start() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::startSection(secID); + } +#endif + } - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::createProfileSection(secName, &secID); - } - #else - secID = 0; - #endif - } - - void start() { - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::startSection(secID); - } - #endif - } - - void stop() { - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::stopSection(secID); - } - #endif - } - - ~ProfilingSection() { - #if defined( KOKKOS_ENABLE_PROFILING ) - if(Kokkos::Profiling::profileLibraryLoaded()) { - Kokkos::Profiling::destroyProfileSection(secID); - } - #endif - } - - std::string getName() { - return secName; - } - - uint32_t getSectionID() { - return secID; - } - -protected: - const std::string secName; - uint32_t secID; + void stop() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::stopSection(secID); + } +#endif + } + ~ProfilingSection() { +#if defined(KOKKOS_ENABLE_PROFILING) + if (Kokkos::Profiling::profileLibraryLoaded()) { + Kokkos::Profiling::destroyProfileSection(secID); + } +#endif + } + + std::string getName() { return secName; } + + uint32_t getSectionID() { return secID; } + + protected: + const std::string secName; + uint32_t secID; }; -} -} +} // namespace Profiling +} // namespace Kokkos -#endif \ No newline at end of file +#endif diff --git a/lib/kokkos/core/src/Kokkos_Qthreads.hpp b/lib/kokkos/core/src/Kokkos_Qthreads.hpp index 16702f8647..e10bd48593 100644 --- a/lib/kokkos/core/src/Kokkos_Qthreads.hpp +++ b/lib/kokkos/core/src/Kokkos_Qthreads.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_QTHREADS_HPP #include -#if defined( KOKKOS_ENABLE_QTHREADS ) +#if defined(KOKKOS_ENABLE_QTHREADS) #include @@ -76,9 +77,9 @@ namespace Impl { class QthreadsExec; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -86,26 +87,26 @@ namespace Kokkos { /** \brief Execution space supported by Qthreads */ class Qthreads { -public: + public: //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as an execution space - typedef Qthreads execution_space; - typedef Kokkos::HostSpace memory_space; + typedef Qthreads execution_space; + typedef Kokkos::HostSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device< execution_space, memory_space > device_type; + typedef Kokkos::Device device_type; - typedef Kokkos::LayoutRight array_layout; - typedef memory_space::size_type size_type; + typedef Kokkos::LayoutRight array_layout; + typedef memory_space::size_type size_type; - typedef ScratchMemorySpace< Qthreads > scratch_memory_space; + typedef ScratchMemorySpace scratch_memory_space; //@} /*------------------------------------------------------------------------*/ /** \brief Initialization will construct one or more instances */ - static Qthreads & instance( int = 0 ); + static Qthreads& instance(int = 0); /** \brief Set the execution space to a "sleep" state. * @@ -143,11 +144,11 @@ public: /** \brief Return maximum amount of concurrency */ static int concurrency(); - static void initialize( int thread_count ); + static void initialize(int thread_count); static void finalize(); /** \brief Print configuration information to the given output stream. */ - static void print_configuration( std::ostream &, const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); int shepherd_size() const; int shepherd_worker_size() const; @@ -155,7 +156,7 @@ public: static const char* name(); }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -163,39 +164,33 @@ namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Qthreads::memory_space - , Kokkos::Qthreads::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Qthreads::memory_space - , Kokkos::Qthreads::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Qthreads::memory_space, Kokkos::Qthreads::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) {} - inline static void verify( const void * ) {} + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl +} // namespace Impl -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ #include #include -//#include // Uncomment when Tasking working. -//#include // Uncomment when Tasking working. - -#endif // #define KOKKOS_ENABLE_QTHREADS -#endif // #define KOKKOS_QTHREADS_HPP +//#include // Uncomment when Tasking +// working. #include // Uncomment when +// Tasking working. +#endif // #define KOKKOS_ENABLE_QTHREADS +#endif // #define KOKKOS_QTHREADS_HPP diff --git a/lib/kokkos/core/src/Kokkos_ROCm.hpp b/lib/kokkos/core/src/Kokkos_ROCm.hpp index 96207e73c6..57113452b8 100644 --- a/lib/kokkos/core/src/Kokkos_ROCm.hpp +++ b/lib/kokkos/core/src/Kokkos_ROCm.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,12 +47,12 @@ #include -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) class dim3 { -public: -int x,y,z; -dim3(int _x, int _y, int _z):x(_x),y(_y),z(_z) {}; + public: + int x, y, z; + dim3(int _x, int _y, int _z) : x(_x), y(_y), z(_z){}; }; #include @@ -74,9 +75,9 @@ dim3(int _x, int _y, int _z):x(_x),y(_y),z(_z) {}; #include #include -#if defined( __HCC_ACCELERATOR__ ) +#if defined(__HCC_ACCELERATOR__) -using namespace ::Concurrency::precise_math ; +using namespace ::Concurrency::precise_math; #endif @@ -84,9 +85,9 @@ using namespace ::Concurrency::precise_math ; namespace Kokkos { namespace Impl { -class ROCmExec ; -} // namespace Impl -} // namespace Kokkos +class ROCmExec; +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -95,30 +96,29 @@ namespace Experimental { /// \class ROCm /// \brief Kokkos device for multicore processors in the host memory space. class ROCm { -public: + public: //------------------------------------ //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as a kokkos execution space - typedef ROCm execution_space ; - typedef ROCmSpace memory_space ; - typedef Kokkos::Device device_type; + typedef ROCm execution_space; + typedef ROCmSpace memory_space; + typedef Kokkos::Device device_type; - typedef LayoutLeft array_layout ; - typedef HostSpace::size_type size_type ; + typedef LayoutLeft array_layout; + typedef HostSpace::size_type size_type; - typedef ScratchMemorySpace< ROCm > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; ~ROCm() {} ROCm(); -// explicit ROCm( const int instance_id ); - - ROCm( ROCm && ) = default ; - ROCm( const ROCm & ) = default ; - ROCm & operator = ( ROCm && ) = default ; - ROCm & operator = ( const ROCm & ) = default ; + // explicit ROCm( const int instance_id ); + ROCm(ROCm&&) = default; + ROCm(const ROCm&) = default; + ROCm& operator=(ROCm&&) = default; + ROCm& operator=(const ROCm&) = default; //@} //------------------------------------ @@ -126,7 +126,7 @@ public: //@{ KOKKOS_INLINE_FUNCTION static int in_parallel() { -#if defined( __HCC_ACCELERATOR__ ) +#if defined(__HCC_ACCELERATOR__) return true; #else return false; @@ -134,122 +134,109 @@ public: } /** \brief Set the device in a "sleep" state. */ - static bool sleep() ; + static bool sleep(); /** \brief Wake the device from the 'sleep' state. A noop for OpenMP. */ - static bool wake() ; + static bool wake(); /** \brief Wait until all dispatched functors complete. A noop for OpenMP. */ static void impl_static_fence(); - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence(); - #else +#else void fence() const; - #endif - +#endif /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); /// \brief Free any resources being consumed by the device. - static void finalize() ; + static void finalize(); /** \brief Initialize the device. * */ struct SelectDevice { - int rocm_device_id ; + int rocm_device_id; SelectDevice() : rocm_device_id(1) {} - explicit SelectDevice( int id ) : rocm_device_id( id+1 ) {} + explicit SelectDevice(int id) : rocm_device_id(id + 1) {} }; - int rocm_device() const { return m_device ; } - bool isAPU(); - bool isAPU(int device); + int rocm_device() const { return m_device; } + bool isAPU(); + bool isAPU(int device); - static void initialize( const SelectDevice = SelectDevice()); + static void initialize(const SelectDevice = SelectDevice()); static int is_initialized(); -// static size_type device_arch(); + // static size_type device_arch(); -// static size_type detect_device_count(); + // static size_type detect_device_count(); - - static int concurrency() ; + static int concurrency(); static const char* name(); -private: - int m_device ; + private: + int m_device; }; -} -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Experimental::ROCmSpace - , Kokkos::Experimental::ROCm::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Experimental::ROCm::memory_space - , Kokkos::Experimental::ROCm::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Experimental::ROCm::memory_space, + Kokkos::Experimental::ROCm::scratch_memory_space> { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::HostSpace - , Kokkos::Experimental::ROCm::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::HostSpace, Kokkos::Experimental::ROCm::scratch_memory_space> { enum { value = false }; - inline static void verify( void ) { Kokkos::Experimental::ROCmSpace::access_error(); } - inline static void verify( const void * p ) { Kokkos::Experimental::ROCmSpace::access_error(p); } + inline static void verify(void) { + Kokkos::Experimental::ROCmSpace::access_error(); + } + inline static void verify(const void* p) { + Kokkos::Experimental::ROCmSpace::access_error(p); + } }; -} // namespace Experimental -} // namespace Kokkos - - - - +} // namespace Impl +} // namespace Kokkos #define threadIdx_x (hc_get_workitem_id(0)) #define threadIdx_y (hc_get_workitem_id(1)) #define threadIdx_z (hc_get_workitem_id(2)) -#define blockIdx_x (hc_get_group_id(0)) -#define blockIdx_y (hc_get_group_id(1)) -#define blockIdx_z (hc_get_group_id(2)) +#define blockIdx_x (hc_get_group_id(0)) +#define blockIdx_y (hc_get_group_id(1)) +#define blockIdx_z (hc_get_group_id(2)) -#define blockDim_x (hc_get_group_size(0)) -#define blockDim_y (hc_get_group_size(1)) -#define blockDim_z (hc_get_group_size(2)) - -#define gridDim_x (hc_get_num_groups(0)) -#define gridDim_y (hc_get_num_groups(1)) -#define gridDim_z (hc_get_num_groups(2)) +#define blockDim_x (hc_get_group_size(0)) +#define blockDim_y (hc_get_group_size(1)) +#define blockDim_z (hc_get_group_size(2)) +#define gridDim_x (hc_get_num_groups(0)) +#define gridDim_y (hc_get_num_groups(1)) +#define gridDim_z (hc_get_num_groups(2)) #include #include #endif #endif - - diff --git a/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp b/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp index c0b7158fde..36017cd40f 100644 --- a/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_ROCmSpace.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -46,7 +47,7 @@ #include -#if defined( KOKKOS_ENABLE_ROCM ) +#if defined(KOKKOS_ENABLE_ROCM) #include #include @@ -54,7 +55,6 @@ #include - /*--------------------------------------------------------------------------*/ namespace Kokkos { @@ -62,30 +62,28 @@ namespace Experimental { /** \brief ROCm on-device memory management */ class ROCmSpace { -public: - + public: //! Tag this class as a kokkos memory space - typedef ROCmSpace memory_space ; - typedef Kokkos::Experimental::ROCm execution_space ; - typedef Kokkos::Device device_type; + typedef ROCmSpace memory_space; + typedef Kokkos::Experimental::ROCm execution_space; + typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef unsigned int size_type; /*--------------------------------*/ ROCmSpace(); - ROCmSpace( ROCmSpace && rhs ) = default ; - ROCmSpace( const ROCmSpace & rhs ) = default ; - ROCmSpace & operator = ( ROCmSpace && rhs ) = default ; - ROCmSpace & operator = ( const ROCmSpace & rhs ) = default ; - ~ROCmSpace() = default ; + ROCmSpace(ROCmSpace&& rhs) = default; + ROCmSpace(const ROCmSpace& rhs) = default; + ROCmSpace& operator=(ROCmSpace&& rhs) = default; + ROCmSpace& operator=(const ROCmSpace& rhs) = default; + ~ROCmSpace() = default; /**\brief Allocate untracked memory in the rocm space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the rocm space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; }; @@ -93,23 +91,23 @@ public: /*--------------------------------*/ /** \brief Error reporting for HostSpace attempt to access ROCmSpace */ static void access_error(); - static void access_error( const void * const ); - -private: + static void access_error(const void* const); - int m_device ; ///< Which ROCm device + private: + int m_device; ///< Which ROCm device static constexpr const char* m_name = "ROCm"; - friend class Kokkos::Impl::SharedAllocationRecord< Kokkos::Experimental::ROCmSpace , void > ; + friend class Kokkos::Impl::SharedAllocationRecord< + Kokkos::Experimental::ROCmSpace, void>; }; -} // namespace Experimental +} // namespace Experimental namespace Impl { -void * rocm_device_allocate(int); -void * rocm_hostpinned_allocate(int); -void rocm_device_free(void * ); +void* rocm_device_allocate(int); +void* rocm_hostpinned_allocate(int); +void rocm_device_free(void*); /// \brief Initialize lock array for arbitrary size atomics. /// @@ -128,10 +126,11 @@ void init_lock_arrays_rocm_space(); /// If the array is not yet allocated it will do so. int* atomic_lock_array_rocm_space_ptr(bool deallocate = false); -/// \brief Retrieve the pointer to the scratch array for team and thread private global memory. +/// \brief Retrieve the pointer to the scratch array for team and thread private +/// global memory. /// /// Team and Thread private scratch allocations in -/// global memory are acquired via locks. +/// global memory are aquired via locks. /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* scratch_lock_array_rocm_space_ptr(bool deallocate = false); @@ -143,55 +142,51 @@ int* scratch_lock_array_rocm_space_ptr(bool deallocate = false); /// This function retrieves the lock array pointer. /// If the array is not yet allocated it will do so. int* threadid_lock_array_rocm_space_ptr(bool deallocate = false); -} -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ - namespace Kokkos { namespace Experimental { /** \brief Host memory that is accessible to ROCm execution space * through ROCm's host-pinned memory allocation. */ class ROCmHostPinnedSpace { -public: - + public: //! Tag this class as a kokkos memory space /** \brief Memory is in HostSpace so use the HostSpace::execution_space */ - typedef HostSpace::execution_space execution_space ; - typedef ROCmHostPinnedSpace memory_space ; - typedef Kokkos::Device device_type; - typedef unsigned int size_type ; + typedef HostSpace::execution_space execution_space; + typedef ROCmHostPinnedSpace memory_space; + typedef Kokkos::Device device_type; + typedef unsigned int size_type; /*--------------------------------*/ ROCmHostPinnedSpace(); - ROCmHostPinnedSpace( ROCmHostPinnedSpace && rhs ) = default ; - ROCmHostPinnedSpace( const ROCmHostPinnedSpace & rhs ) = default ; - ROCmHostPinnedSpace & operator = ( ROCmHostPinnedSpace && rhs ) = default ; - ROCmHostPinnedSpace & operator = ( const ROCmHostPinnedSpace & rhs ) = default ; - ~ROCmHostPinnedSpace() = default ; + ROCmHostPinnedSpace(ROCmHostPinnedSpace&& rhs) = default; + ROCmHostPinnedSpace(const ROCmHostPinnedSpace& rhs) = default; + ROCmHostPinnedSpace& operator=(ROCmHostPinnedSpace&& rhs) = default; + ROCmHostPinnedSpace& operator=(const ROCmHostPinnedSpace& rhs) = default; + ~ROCmHostPinnedSpace() = default; /**\brief Allocate untracked memory in the space */ - void * allocate( const size_t arg_alloc_size ) const ; + void* allocate(const size_t arg_alloc_size) const; /**\brief Deallocate untracked memory in the space */ - void deallocate( void * const arg_alloc_ptr - , const size_t arg_alloc_size ) const ; + void deallocate(void* const arg_alloc_ptr, const size_t arg_alloc_size) const; /**\brief Return Name of the MemorySpace */ static constexpr const char* name() { return m_name; }; -private: - + private: static constexpr const char* m_name = "ROCmHostPinned"; /*--------------------------------*/ }; -} // namespace Experimental -} // namespace Kokkos +} // namespace Experimental +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -199,65 +194,71 @@ private: namespace Kokkos { namespace Impl { -static_assert( Kokkos::Impl::MemorySpaceAccess< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace >::assignable , "" ); +static_assert(Kokkos::Impl::MemorySpaceAccess< + Kokkos::Experimental::ROCmSpace, + Kokkos::Experimental::ROCmSpace>::assignable, + ""); //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::Experimental::ROCmSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // HostSpace::execution_space == ROCmHostPinnedSpace::execution_space enum { assignable = true }; enum { accessible = true }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; //---------------------------------------- -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmSpace , Kokkos::HostSpace > { +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmHostPinnedSpace > { +template <> +struct MemorySpaceAccess { // ROCmSpace::execution_space != ROCmHostPinnedSpace::execution_space enum { assignable = false }; - enum { accessible = true }; // ROCmSpace::execution_space - enum { deepcopy = true }; + enum { accessible = true }; // ROCmSpace::execution_space + enum { deepcopy = true }; }; - //---------------------------------------- // ROCmHostPinnedSpace::execution_space == HostSpace::execution_space // ROCmHostPinnedSpace accessible to both ROCm and Host -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::HostSpace > { - enum { assignable = false }; // Cannot access from ROCm - enum { accessible = true }; // ROCmHostPinnedSpace::execution_space - enum { deepcopy = true }; +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from ROCm + enum { accessible = true }; // ROCmHostPinnedSpace::execution_space + enum { deepcopy = true }; }; -template<> -struct MemorySpaceAccess< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmSpace > { - enum { assignable = false }; // Cannot access from Host +template <> +struct MemorySpaceAccess { + enum { assignable = false }; // Cannot access from Host enum { accessible = false }; - enum { deepcopy = true }; + enum { deepcopy = true }; }; -}; +}; // namespace Impl //---------------------------------------- -} // namespace Kokkos::Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -265,171 +266,187 @@ struct MemorySpaceAccess< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Ex namespace Kokkos { namespace Impl { -hc::completion_future DeepCopyAsyncROCm( void * dst , const void * src , size_t n); +hc::completion_future DeepCopyAsyncROCm(void* dst, const void* src, size_t n); -template<> struct DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm> -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template struct DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy( + dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + hc::completion_future fut = DeepCopyAsyncROCm(dst, src, n); fut.wait(); -// DeepCopy (dst,src,n); + // DeepCopy (dst,src,n); } }; -template struct DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , Kokkos::Experimental::ROCm>( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -template -struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -template<> struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm> -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , HostSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template<> struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm > -{ - DeepCopy( void * dst , const void * src , size_t ); - DeepCopy( const Kokkos::Experimental::ROCm & , void * dst , const void * src , size_t ); +template <> +struct DeepCopy { + DeepCopy(void* dst, const void* src, size_t); + DeepCopy(const Kokkos::Experimental::ROCm&, void* dst, const void* src, + size_t); }; -template -struct DeepCopy< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmHostPinnedSpace , ExecutionSpace> -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmSpace , HostSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + hc::completion_future fut = DeepCopyAsyncROCm(dst, src, n); fut.wait(); -// DeepCopyROCm (dst,src,n); + // DeepCopyROCm (dst,src,n); } }; -template struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + hc::completion_future fut = DeepCopyAsyncROCm(dst, src, n); fut.wait(); -// DeepCopyROCm (dst,src,n); + // DeepCopyROCm (dst,src,n); } }; +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - -template struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } - - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); -// hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); -// fut.wait(); -// DeepCopyAsyncROCm (dst,src,n); - DeepCopy (dst,src,n); + // hc::completion_future fut = DeepCopyAsyncROCm (dst,src,n); + // fut.wait(); + // DeepCopyAsyncROCm (dst,src,n); + DeepCopy(dst, src, n); } }; -template struct DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , HostSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< Kokkos::Experimental::ROCmHostPinnedSpace , HostSpace , Kokkos::Experimental::ROCm>( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -template -struct DeepCopy< HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace , ExecutionSpace > -{ - inline - DeepCopy( void * dst , const void * src , size_t n ) - { (void) DeepCopy< HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace , Kokkos::Experimental::ROCm >( dst , src , n ); } +template +struct DeepCopy { + inline DeepCopy(void* dst, const void* src, size_t n) { + (void)DeepCopy(dst, src, n); + } - inline - DeepCopy( const ExecutionSpace& exec, void * dst , const void * src , size_t n ) - { + inline DeepCopy(const ExecutionSpace& exec, void* dst, const void* src, + size_t n) { exec.fence(); - DeepCopy (dst,src,n); + DeepCopy(dst, src, n); } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -438,60 +455,70 @@ namespace Kokkos { namespace Impl { /** Running in ROCmSpace attempting to access HostSpace: error */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::Experimental::ROCmSpace , Kokkos::HostSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("ROCm code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("ROCm code attempted to access HostSpace memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("ROCm code attempted to access HostSpace memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("ROCm code attempted to access HostSpace memory"); + } }; /** Running in ROCmSpace accessing ROCmHostPinnedSpace: ok */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::Experimental::ROCmSpace , Kokkos::Experimental::ROCmHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Experimental::ROCmSpace, + Kokkos::Experimental::ROCmHostPinnedSpace> { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) { } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) { } + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; /** Running in ROCmSpace attempting to access an unknown space: error */ -template< class OtherSpace > +template struct VerifyExecutionCanAccessMemorySpace< - typename enable_if< ! is_same::value , Kokkos::Experimental::ROCmSpace >::type , - OtherSpace > -{ + typename enable_if< + !is_same::value, + Kokkos::Experimental::ROCmSpace>::type, + OtherSpace> { enum { value = false }; - KOKKOS_INLINE_FUNCTION static void verify( void ) - { Kokkos::abort("ROCm code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(void) { + Kokkos::abort("ROCm code attempted to access unknown Space memory"); + } - KOKKOS_INLINE_FUNCTION static void verify( const void * ) - { Kokkos::abort("ROCm code attempted to access unknown Space memory"); } + KOKKOS_INLINE_FUNCTION static void verify(const void*) { + Kokkos::abort("ROCm code attempted to access unknown Space memory"); + } }; //---------------------------------------------------------------------------- /** Running in HostSpace attempting to access ROCmSpace */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experimental::ROCmSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace { enum { value = false }; - inline static void verify( void ) { Kokkos::Experimental::ROCmSpace::access_error(); } - inline static void verify( const void * p ) { Kokkos::Experimental::ROCmSpace::access_error(p); } + inline static void verify(void) { + Kokkos::Experimental::ROCmSpace::access_error(); + } + inline static void verify(const void* p) { + Kokkos::Experimental::ROCmSpace::access_error(p); + } }; /** Running in HostSpace accessing ROCmHostPinnedSpace is OK */ -template<> -struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experimental::ROCmHostPinnedSpace > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::HostSpace, Kokkos::Experimental::ROCmHostPinnedSpace> { enum { value = true }; - KOKKOS_INLINE_FUNCTION static void verify( void ) {} - KOKKOS_INLINE_FUNCTION static void verify( const void * ) {} + KOKKOS_INLINE_FUNCTION static void verify(void) {} + KOKKOS_INLINE_FUNCTION static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -499,128 +526,112 @@ struct VerifyExecutionCanAccessMemorySpace< Kokkos::HostSpace , Kokkos::Experime namespace Kokkos { namespace Impl { -template<> -class SharedAllocationRecord< Kokkos::Experimental::ROCmSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - typedef SharedAllocationRecord< void , void > RecordBase ; - - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; - - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG - static RecordBase s_root_record ; + static RecordBase s_root_record; #endif - const Kokkos::Experimental::ROCmSpace m_space ; - -protected: + const Kokkos::Experimental::ROCmSpace m_space; + protected: ~SharedAllocationRecord(); - SharedAllocationRecord( const Kokkos::Experimental::ROCmSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); + SharedAllocationRecord( + const Kokkos::Experimental::ROCmSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); -public: + public: + std::string get_label() const; - std::string get_label() const ; - - static SharedAllocationRecord * allocate( const Kokkos::Experimental::ROCmSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static SharedAllocationRecord* allocate( + const Kokkos::Experimental::ROCmSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::ROCmSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked( + const Kokkos::Experimental::ROCmSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static void print_records( std::ostream & , const Kokkos::Experimental::ROCmSpace & , bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::ROCmSpace&, + bool detail = false); }; -template<> -class SharedAllocationRecord< Kokkos::Experimental::ROCmHostPinnedSpace , void > - : public SharedAllocationRecord< void , void > -{ -private: - - typedef SharedAllocationRecord< void , void > RecordBase ; +template <> +class SharedAllocationRecord + : public SharedAllocationRecord { + private: + typedef SharedAllocationRecord RecordBase; - SharedAllocationRecord( const SharedAllocationRecord & ) = delete ; - SharedAllocationRecord & operator = ( const SharedAllocationRecord & ) = delete ; + SharedAllocationRecord(const SharedAllocationRecord&) = delete; + SharedAllocationRecord& operator=(const SharedAllocationRecord&) = delete; - static void deallocate( RecordBase * ); + static void deallocate(RecordBase*); #ifdef KOKKOS_DEBUG - static RecordBase s_root_record ; + static RecordBase s_root_record; #endif - const Kokkos::Experimental::ROCmHostPinnedSpace m_space ; - -protected: + const Kokkos::Experimental::ROCmHostPinnedSpace m_space; + protected: ~SharedAllocationRecord(); SharedAllocationRecord() : RecordBase(), m_space() {} - SharedAllocationRecord( const Kokkos::Experimental::ROCmHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - , const RecordBase::function_type arg_dealloc = & deallocate - ); - -public: + SharedAllocationRecord( + const Kokkos::Experimental::ROCmHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size, + const RecordBase::function_type arg_dealloc = &deallocate); - std::string get_label() const ; + public: + std::string get_label() const; - static SharedAllocationRecord * allocate( const Kokkos::Experimental::ROCmHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size - ); + static SharedAllocationRecord* allocate( + const Kokkos::Experimental::ROCmHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Allocate tracked memory in the space */ - static - void * allocate_tracked( const Kokkos::Experimental::ROCmHostPinnedSpace & arg_space - , const std::string & arg_label - , const size_t arg_alloc_size ); + static void* allocate_tracked( + const Kokkos::Experimental::ROCmHostPinnedSpace& arg_space, + const std::string& arg_label, const size_t arg_alloc_size); /**\brief Reallocate tracked memory in the space */ - static - void * reallocate_tracked( void * const arg_alloc_ptr - , const size_t arg_alloc_size ); + static void* reallocate_tracked(void* const arg_alloc_ptr, + const size_t arg_alloc_size); /**\brief Deallocate tracked memory in the space */ - static - void deallocate_tracked( void * const arg_alloc_ptr ); + static void deallocate_tracked(void* const arg_alloc_ptr); + static SharedAllocationRecord* get_record(void* arg_alloc_ptr); - static SharedAllocationRecord * get_record( void * arg_alloc_ptr ); - - static void print_records( std::ostream & , const Kokkos::Experimental::ROCmHostPinnedSpace & , bool detail = false ); + static void print_records(std::ostream&, + const Kokkos::Experimental::ROCmHostPinnedSpace&, + bool detail = false); }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_ROCM ) */ #endif /* #define KOKKOS_ROCMSPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp b/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp index 86d803ccc9..c2337f08a1 100644 --- a/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp +++ b/lib/kokkos/core/src/Kokkos_ScratchSpace.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -55,158 +56,157 @@ namespace Kokkos { /** \brief Scratch memory space associated with an execution space. * */ -template< class ExecSpace > +template class ScratchMemorySpace { - static_assert (is_execution_space::value,"Instantiating ScratchMemorySpace on non-execution-space type."); -public: + static_assert( + is_execution_space::value, + "Instantiating ScratchMemorySpace on non-execution-space type."); + public: // Alignment of memory chunks returned by 'get' // must be a power of two enum { ALIGN = 8 }; -private: - - mutable char * m_iter_L0 ; - char * m_end_L0 ; - mutable char * m_iter_L1 ; - char * m_end_L1 ; - + private: + mutable char* m_iter_L0; + char* m_end_L0; + mutable char* m_iter_L1; + char* m_end_L1; mutable int m_multiplier; mutable int m_offset; mutable int m_default_level; ScratchMemorySpace(); - ScratchMemorySpace & operator = ( const ScratchMemorySpace & ); - - enum { MASK = ALIGN - 1 }; // Alignment used by View::shmem_size + ScratchMemorySpace& operator=(const ScratchMemorySpace&); -public: + enum { MASK = ALIGN - 1 }; // Alignment used by View::shmem_size + public: //! Tag this class as a memory space - typedef ScratchMemorySpace memory_space ; - typedef ExecSpace execution_space ; + typedef ScratchMemorySpace memory_space; + typedef ExecSpace execution_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; - typedef typename ExecSpace::array_layout array_layout ; - typedef typename ExecSpace::size_type size_type ; + typedef typename ExecSpace::array_layout array_layout; + typedef typename ExecSpace::size_type size_type; - template< typename IntType > - KOKKOS_INLINE_FUNCTION static - IntType align( const IntType & size ) - { return ( size + MASK ) & ~MASK ; } + template + KOKKOS_INLINE_FUNCTION static IntType align(const IntType& size) { + return (size + MASK) & ~MASK; + } - template< typename IntType > - KOKKOS_INLINE_FUNCTION - void* get_shmem (const IntType& size, int level = -1) const { - if(level == -1) - level = m_default_level; - if(level == 0) { - void* tmp = m_iter_L0 + m_offset * align (size); - if (m_end_L0 < (m_iter_L0 += align (size) * m_multiplier)) { - m_iter_L0 -= align (size) * m_multiplier; // put it back like it was - #ifdef KOKKOS_DEBUG + template + KOKKOS_INLINE_FUNCTION void* get_shmem(const IntType& size, + int level = -1) const { + if (level == -1) level = m_default_level; + if (level == 0) { + void* tmp = m_iter_L0 + m_offset * align(size); + if (m_end_L0 < (m_iter_L0 += align(size) * m_multiplier)) { + m_iter_L0 -= align(size) * m_multiplier; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L0-m_iter_L0)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L0 - m_iter_L0)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; } else { - void* tmp = m_iter_L1 + m_offset * align (size); - if (m_end_L1 < (m_iter_L1 += align (size) * m_multiplier)) { - m_iter_L1 -= align (size) * m_multiplier; // put it back like it was - #ifdef KOKKOS_DEBUG + void* tmp = m_iter_L1 + m_offset * align(size); + if (m_end_L1 < (m_iter_L1 += align(size) * m_multiplier)) { + m_iter_L1 -= align(size) * m_multiplier; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L1-m_iter_L1)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L1 - m_iter_L1)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; - } } - KOKKOS_INLINE_FUNCTION - void* get_shmem_aligned (const ptrdiff_t size, const ptrdiff_t alignment, int level = -1) const { - if(level == -1) - level = m_default_level; - if(level == 0) { - - char* previous = m_iter_L0; - const ptrdiff_t missalign = size_t(m_iter_L0)%alignment; - if(missalign) m_iter_L0 += alignment-missalign; + void* get_shmem_aligned(const ptrdiff_t size, const ptrdiff_t alignment, + int level = -1) const { + if (level == -1) level = m_default_level; + if (level == 0) { + char* previous = m_iter_L0; + const ptrdiff_t missalign = size_t(m_iter_L0) % alignment; + if (missalign) m_iter_L0 += alignment - missalign; void* tmp = m_iter_L0 + m_offset * size; if (m_end_L0 < (m_iter_L0 += size * m_multiplier)) { - m_iter_L0 = previous; // put it back like it was - #ifdef KOKKOS_DEBUG + m_iter_L0 = previous; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L0-m_iter_L0)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L0 - m_iter_L0)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; } else { - - char* previous = m_iter_L1; - const ptrdiff_t missalign = size_t(m_iter_L1)%alignment; - if(missalign) m_iter_L1 += alignment-missalign; + char* previous = m_iter_L1; + const ptrdiff_t missalign = size_t(m_iter_L1) % alignment; + if (missalign) m_iter_L1 += alignment - missalign; void* tmp = m_iter_L1 + m_offset * size; if (m_end_L1 < (m_iter_L1 += size * m_multiplier)) { - m_iter_L1 = previous; // put it back like it was - #ifdef KOKKOS_DEBUG + m_iter_L1 = previous; // put it back like it was +#ifdef KOKKOS_DEBUG // mfh 23 Jun 2015: printf call consumes 25 registers // in a CUDA build, so only print in debug mode. The // function still returns NULL if not enough memory. - printf ("ScratchMemorySpace<...>::get_shmem: Failed to allocate " - "%ld byte(s); remaining capacity is %ld byte(s)\n", long(size), - long(m_end_L1-m_iter_L1)); - #endif // KOKKOS_DEBUG + printf( + "ScratchMemorySpace<...>::get_shmem: Failed to allocate " + "%ld byte(s); remaining capacity is %ld byte(s)\n", + long(size), long(m_end_L1 - m_iter_L1)); +#endif // KOKKOS_DEBUG tmp = 0; } return tmp; - } } - template< typename IntType > - KOKKOS_INLINE_FUNCTION - ScratchMemorySpace( void * ptr_L0 , const IntType & size_L0 , void * ptr_L1 = NULL , const IntType & size_L1 = 0) - : m_iter_L0( (char *) ptr_L0 ) - , m_end_L0( m_iter_L0 + size_L0 ) - , m_iter_L1( (char *) ptr_L1 ) - , m_end_L1( m_iter_L1 + size_L1 ) - , m_multiplier( 1 ) - , m_offset( 0 ) - , m_default_level( 0 ) - {} + template + KOKKOS_INLINE_FUNCTION ScratchMemorySpace(void* ptr_L0, + const IntType& size_L0, + void* ptr_L1 = NULL, + const IntType& size_L1 = 0) + : m_iter_L0((char*)ptr_L0), + m_end_L0(m_iter_L0 + size_L0), + m_iter_L1((char*)ptr_L1), + m_end_L1(m_iter_L1 + size_L1), + m_multiplier(1), + m_offset(0), + m_default_level(0) {} KOKKOS_INLINE_FUNCTION - const ScratchMemorySpace& set_team_thread_mode(const int& level, const int& multiplier, const int& offset) const { + const ScratchMemorySpace& set_team_thread_mode(const int& level, + const int& multiplier, + const int& offset) const { m_default_level = level; - m_multiplier = multiplier; - m_offset = offset; + m_multiplier = multiplier; + m_offset = offset; return *this; } }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_SCRATCHSPACE_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Serial.hpp b/lib/kokkos/core/src/Kokkos_Serial.hpp index 5821b0c0c5..e30598be21 100644 --- a/lib/kokkos/core/src/Kokkos_Serial.hpp +++ b/lib/kokkos/core/src/Kokkos_Serial.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -48,7 +49,7 @@ #define KOKKOS_SERIAL_HPP #include -#if defined( KOKKOS_ENABLE_SERIAL ) +#if defined(KOKKOS_ENABLE_SERIAL) #include #include @@ -83,24 +84,24 @@ namespace Kokkos { /// threads, or if you want to explore different combinations of MPI /// and shared-memory parallel programming models. class Serial { -public: + public: //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as an execution space: - typedef Serial execution_space ; + typedef Serial execution_space; //! The size_type typedef best suited for this device. - typedef HostSpace::size_type size_type ; + typedef HostSpace::size_type size_type; //! This device's preferred memory space. - typedef HostSpace memory_space ; + typedef HostSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; //! This device's preferred array layout. - typedef LayoutRight array_layout ; + typedef LayoutRight array_layout; /// \brief Scratch memory space - typedef ScratchMemorySpace< Kokkos::Serial > scratch_memory_space ; + typedef ScratchMemorySpace scratch_memory_space; //@} @@ -110,7 +111,7 @@ public: /// For the Serial device, this method always returns false, /// because parallel_for or parallel_reduce with the Serial device /// always execute sequentially. - inline static int in_parallel() { return false ; } + inline static int in_parallel() { return false; } /// \brief Wait until all dispatched functors complete. /// @@ -120,26 +121,27 @@ public: /// device have completed. static void impl_static_fence() {} - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence() {} - #else +#else void fence() const {} - #endif +#endif /** \brief Return the maximum amount of concurrency. */ - static int concurrency() {return 1;} + static int concurrency() { return 1; } //! Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool /* detail */ = false ) {} + static void print_configuration(std::ostream&, + const bool /* detail */ = false) {} #ifdef KOKKOS_ENABLE_DEPRECATED_CODE static bool sleep(); static bool wake(); - static void initialize( unsigned threads_count = 1 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 , - bool allow_asynchronous_threadpool = false); + static void initialize(unsigned threads_count = 1, + unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0, + bool allow_asynchronous_threadpool = false); static bool is_initialized(); @@ -148,12 +150,14 @@ public: //-------------------------------------------------------------------------- - inline static int thread_pool_size( int = 0 ) { return 1 ; } - KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0 ; } + inline static int thread_pool_size(int = 0) { return 1; } + KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0; } //-------------------------------------------------------------------------- - KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { return thread_pool_rank(); } + KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { + return thread_pool_rank(); + } inline static unsigned max_hardware_threads() { return thread_pool_size(0); } #else static void impl_initialize(); @@ -165,20 +169,24 @@ public: //-------------------------------------------------------------------------- - inline static int impl_thread_pool_size( int = 0 ) { return 1 ; } - KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0 ; } + inline static int impl_thread_pool_size(int = 0) { return 1; } + KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0; } //-------------------------------------------------------------------------- - KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { return impl_thread_pool_rank(); } - inline static unsigned impl_max_hardware_threads() { return impl_thread_pool_size(0); } + KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { + return impl_thread_pool_rank(); + } + inline static unsigned impl_max_hardware_threads() { + return impl_thread_pool_size(0); + } #endif static const char* name(); //-------------------------------------------------------------------------- }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -186,30 +194,24 @@ public: namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Serial::memory_space - , Kokkos::Serial::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Serial::memory_space - , Kokkos::Serial::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Serial::memory_space, Kokkos::Serial::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -218,247 +220,294 @@ namespace Kokkos { namespace Impl { // Resize thread team data scratch memory -void serial_resize_thread_team_data( size_t pool_reduce_bytes - , size_t team_reduce_bytes - , size_t team_shared_bytes - , size_t thread_local_bytes ); +void serial_resize_thread_team_data(size_t pool_reduce_bytes, + size_t team_reduce_bytes, + size_t team_shared_bytes, + size_t thread_local_bytes); -HostThreadTeamData * serial_get_thread_team_data(); +HostThreadTeamData* serial_get_thread_team_data(); } /* namespace Impl */ } /* namespace Kokkos */ - namespace Kokkos { namespace Impl { /* * < Kokkos::Serial , WorkArgTag > - * < WorkArgTag , Impl::enable_if< std::is_same< Kokkos::Serial , Kokkos::DefaultExecutionSpace >::value >::type > + * < WorkArgTag , Impl::enable_if< std::is_same< Kokkos::Serial , + * Kokkos::DefaultExecutionSpace >::value >::type > * */ -template< class ... Properties > -class TeamPolicyInternal< Kokkos::Serial , Properties ... >:public PolicyTraits -{ -private: - - size_t m_team_scratch_size[2] ; - size_t m_thread_scratch_size[2] ; - int m_league_size ; - int m_chunk_size; - -public: - +template +class TeamPolicyInternal + : public PolicyTraits { + private: + size_t m_team_scratch_size[2]; + size_t m_thread_scratch_size[2]; + int m_league_size; + int m_chunk_size; + + public: //! Tag this class as a kokkos execution policy - typedef TeamPolicyInternal execution_policy ; + typedef TeamPolicyInternal execution_policy; - typedef PolicyTraits traits; + typedef PolicyTraits traits; //! Execution space of this execution policy: - typedef Kokkos::Serial execution_space ; + typedef Kokkos::Serial execution_space; - TeamPolicyInternal& operator = (const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; + TeamPolicyInternal& operator=(const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; + m_chunk_size = p.m_chunk_size; return *this; } - template + template friend class TeamPolicyInternal; - template< class ... OtherProperties > - TeamPolicyInternal(const TeamPolicyInternal& p) { - m_league_size = p.m_league_size; - m_team_scratch_size[0] = p.m_team_scratch_size[0]; + template + TeamPolicyInternal( + const TeamPolicyInternal& p) { + m_league_size = p.m_league_size; + m_team_scratch_size[0] = p.m_team_scratch_size[0]; m_thread_scratch_size[0] = p.m_thread_scratch_size[0]; - m_team_scratch_size[1] = p.m_team_scratch_size[1]; + m_team_scratch_size[1] = p.m_team_scratch_size[1]; m_thread_scratch_size[1] = p.m_thread_scratch_size[1]; - m_chunk_size = p.m_chunk_size; + m_chunk_size = p.m_chunk_size; } - //---------------------------------------- #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class FunctorType > - static - int team_size_max( const FunctorType & ) { return 1 ; } + template + static int team_size_max(const FunctorType&) { + return 1; + } - template< class FunctorType > - static - int team_size_recommended( const FunctorType & ) { return 1 ; } + template + static int team_size_recommended(const FunctorType&) { + return 1; + } - template< class FunctorType > - static - int team_size_recommended( const FunctorType & , const int& ) { return 1 ; } + template + static int team_size_recommended(const FunctorType&, const int&) { + return 1; + } #endif - template - int team_size_max( const FunctorType&, const ParallelForTag& ) const { return 1 ; } - template - int team_size_max( const FunctorType&, const ParallelReduceTag& ) const { return 1 ; } - template - int team_size_recommended( const FunctorType&, const ParallelForTag& ) const { return 1 ; } - template - int team_size_recommended( const FunctorType&, const ParallelReduceTag& ) const { return 1 ; } + template + int team_size_max(const FunctorType&, const ParallelForTag&) const { + return 1; + } + template + int team_size_max(const FunctorType&, const ParallelReduceTag&) const { + return 1; + } + template + int team_size_max(const FunctorType&, const ReducerType&, + const ParallelReduceTag&) const { + return 1; + } + template + int team_size_recommended(const FunctorType&, const ParallelForTag&) const { + return 1; + } + template + int team_size_recommended(const FunctorType&, + const ParallelReduceTag&) const { + return 1; + } + template + int team_size_recommended(const FunctorType&, const ReducerType&, + const ParallelReduceTag&) const { + return 1; + } //---------------------------------------- - inline int team_size() const { return 1 ; } - inline int league_size() const { return m_league_size ; } - inline size_t scratch_size(const int& level, int = 0) const { return m_team_scratch_size[level] + m_thread_scratch_size[level]; } + inline int team_size() const { return 1; } + inline int league_size() const { return m_league_size; } + inline size_t scratch_size(const int& level, int = 0) const { + return m_team_scratch_size[level] + m_thread_scratch_size[level]; + } - inline static - int vector_length_max() - { return 1024; } // Use arbitrary large number, is meant as a vectorizable length + inline static int vector_length_max() { + return 1024; + } // Use arbitrary large number, is meant as a vectorizable length - inline static - int scratch_size_max(int level) - { return (level==0? - 1024*32: - 20*1024*1024); + inline static int scratch_size_max(int level) { + return (level == 0 ? 1024 * 32 : 20 * 1024 * 1024); } /** \brief Specify league size, request team size */ - TeamPolicyInternal( const execution_space & - , int league_size_request + TeamPolicyInternal(const execution_space&, int league_size_request #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - , int team_size_request + , + int team_size_request #else - , int /* team_size_request */ + , + int /* team_size_request */ #endif - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - { - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - if(team_size_request > 1) Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); - #endif - } + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) { +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE + if (team_size_request > 1) + Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); +#endif + } + + TeamPolicyInternal(const execution_space&, int league_size_request, + const Kokkos::AUTO_t& /* team_size_request */ + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) {} - TeamPolicyInternal( const execution_space & - , int league_size_request - , const Kokkos::AUTO_t & /* team_size_request */ - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - {} - - TeamPolicyInternal( int league_size_request + TeamPolicyInternal(int league_size_request #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - , int team_size_request + , + int team_size_request #else - , int /* team_size_request */ + , + int /* team_size_request */ #endif - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - { - #ifndef KOKKOS_ENABLE_DEPRECATED_CODE - if(team_size_request > 1) Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); - #endif - } + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) { +#ifndef KOKKOS_ENABLE_DEPRECATED_CODE + if (team_size_request > 1) + Kokkos::abort("Kokkos::abort: Requested Team Size is too large!"); +#endif + } - TeamPolicyInternal( int league_size_request - , const Kokkos::AUTO_t & /* team_size_request */ - , int /* vector_length_request */ = 1 ) - : m_team_scratch_size { 0 , 0 } - , m_thread_scratch_size { 0 , 0 } - , m_league_size( league_size_request ) - , m_chunk_size ( 32 ) - {} + TeamPolicyInternal(int league_size_request, + const Kokkos::AUTO_t& /* team_size_request */ + , + int /* vector_length_request */ = 1) + : m_team_scratch_size{0, 0}, + m_thread_scratch_size{0, 0}, + m_league_size(league_size_request), + m_chunk_size(32) {} - inline int chunk_size() const { return m_chunk_size ; } + inline int chunk_size() const { return m_chunk_size; } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal set_chunk_size(typename traits::index_type chunk_size_) const { + inline TeamPolicyInternal set_chunk_size( + typename traits::index_type chunk_size_) const { TeamPolicyInternal p = *this; - p.m_chunk_size = chunk_size_; + p.m_chunk_size = chunk_size_; return p; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team) const { - TeamPolicyInternal p = *this; + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team) const { + TeamPolicyInternal p = *this; p.m_team_scratch_size[level] = per_team.value; return p; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; p.m_thread_scratch_size[level] = per_thread.value; return p; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) const { - TeamPolicyInternal p = *this; - p.m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) const { + TeamPolicyInternal p = *this; + p.m_team_scratch_size[level] = per_team.value; p.m_thread_scratch_size[level] = per_thread.value; return p; } #else /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal& set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal& set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size(const int& level, + const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal& set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal& set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } #endif - typedef Impl::HostThreadTeamMember< Kokkos::Serial > member_type ; + typedef Impl::HostThreadTeamMember member_type; -protected: + protected: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE /** \brief set chunk_size to a discrete value*/ - inline TeamPolicyInternal internal_set_chunk_size(typename traits::index_type chunk_size_) { + inline TeamPolicyInternal internal_set_chunk_size( + typename traits::index_type chunk_size_) { m_chunk_size = chunk_size_; return *this; } - /** \brief set per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team) { + /** \brief set per team scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team) { m_team_scratch_size[level] = per_team.value; return *this; } - /** \brief set per thread scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerThreadValue& per_thread) { + /** \brief set per thread scratch size for a specific level of the scratch + * hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerThreadValue& per_thread) { m_thread_scratch_size[level] = per_thread.value; return *this; } - /** \brief set per thread and per team scratch size for a specific level of the scratch hierarchy */ - inline TeamPolicyInternal internal_set_scratch_size(const int& level, const PerTeamValue& per_team, const PerThreadValue& per_thread) { - m_team_scratch_size[level] = per_team.value; + /** \brief set per thread and per team scratch size for a specific level of + * the scratch hierarchy */ + inline TeamPolicyInternal internal_set_scratch_size( + const int& level, const PerTeamValue& per_team, + const PerThreadValue& per_thread) { + m_team_scratch_size[level] = per_team.value; m_thread_scratch_size[level] = per_thread.value; return *this; } @@ -474,339 +523,280 @@ protected: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType , - Kokkos::RangePolicy< Traits ... > , - Kokkos::Serial - > -{ -private: - - typedef Kokkos::RangePolicy< Traits ... > Policy ; - - const FunctorType m_functor ; - const Policy m_policy ; - - template< class TagType > - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec() const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i ); - } - } +template +class ParallelFor, Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + + const FunctorType m_functor; + const Policy m_policy; - template< class TagType > - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec() const - { - const TagType t{} ; - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i ); - } + template + typename std::enable_if::value>::type exec() + const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i); } + } -public: + template + typename std::enable_if::value>::type exec() + const { + const TagType t{}; + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i); + } + } - inline - void execute() const - { this-> template exec< typename Policy::work_tag >(); } + public: + inline void execute() const { + this->template exec(); + } - inline - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - {} + inline ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), m_policy(arg_policy) {} }; /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ReducerType , class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReducerType - , Kokkos::Serial - > -{ -private: - - typedef Kokkos::RangePolicy< Traits ... > Policy ; - typedef typename Policy::work_tag WorkTag ; +template +class ParallelReduce, ReducerType, + Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + typedef typename Policy::work_tag WorkTag; - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; - typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , Policy , FunctorType > Analysis ; + typedef FunctorAnalysis + Analysis; - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTagFwd > ValueInit ; + typedef Kokkos::Impl::FunctorValueInit ValueInit; - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; - const FunctorType m_functor ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; + const FunctorType m_functor; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i , update ); - } + template + inline typename std::enable_if::value>::type exec( + reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i, update); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const TagType t{} ; - - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i , update ); - } - } + template + inline typename std::enable_if::value>::type + exec(reference_type update) const { + const TagType t{}; -public: + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i, update); + } + } - inline - void execute() const - { - const size_t pool_reduce_size = - Analysis::value_size( ReducerConditional::select(m_functor , m_reducer) ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = + Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - pointer_type ptr = + pointer_type ptr = m_result_ptr ? m_result_ptr : pointer_type(data.pool_reduce_local()); - reference_type update = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , ptr ); + reference_type update = + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), ptr); - this-> template exec< WorkTag >( update ); + this->template exec(update); - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >:: - final( ReducerConditional::select(m_functor , m_reducer) , ptr ); - } + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), ptr); + } - template< class HostViewType > - ParallelReduce( const FunctorType & arg_functor , - const Policy & arg_policy , - const HostViewType & arg_result_view , - typename std::enable_if< - Kokkos::is_view< HostViewType >::value && - !Kokkos::is_reducer_type::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result_view.data() ) - { - static_assert( Kokkos::is_view< HostViewType >::value - , "Kokkos::Serial reduce result must be a View" ); - - static_assert( std::is_same< typename HostViewType::memory_space , HostSpace >::value - , "Kokkos::Serial reduce result must be a View in HostSpace" ); - } + template + ParallelReduce( + const FunctorType& arg_functor, const Policy& arg_policy, + const HostViewType& arg_result_view, + typename std::enable_if::value && + !Kokkos::is_reducer_type::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(InvalidType()), + m_result_ptr(arg_result_view.data()) { + static_assert(Kokkos::is_view::value, + "Kokkos::Serial reduce result must be a View"); + + static_assert( + std::is_same::value, + "Kokkos::Serial reduce result must be a View in HostSpace"); + } - inline - ParallelReduce( const FunctorType & arg_functor - , Policy arg_policy - , const ReducerType& reducer ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - { - /*static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" );*/ - } + inline ParallelReduce(const FunctorType& arg_functor, Policy arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_policy(arg_policy), + m_reducer(reducer), + m_result_ptr(reducer.view().data()) { + /*static_assert( std::is_same< typename ViewType::memory_space + , Kokkos::HostSpace >::value + , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" + );*/ + } }; - /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ... Traits > -class ParallelScan< FunctorType - , Kokkos::RangePolicy< Traits ... > - , Kokkos::Serial - > -{ -private: +template +class ParallelScan, + Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + typedef typename Policy::work_tag WorkTag; - typedef Kokkos::RangePolicy< Traits ... > Policy ; - typedef typename Policy::work_tag WorkTag ; + typedef FunctorAnalysis + Analysis; - typedef FunctorAnalysis< FunctorPatternInterface::SCAN , Policy , FunctorType > Analysis ; + typedef Kokkos::Impl::FunctorValueInit ValueInit; - typedef Kokkos::Impl::FunctorValueInit< FunctorType , WorkTag > ValueInit ; + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; + const FunctorType m_functor; + const Policy m_policy; - const FunctorType m_functor ; - const Policy m_policy ; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i , update , true ); - } + template + inline typename std::enable_if::value>::type exec( + reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i, update, true); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const TagType t{} ; - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i , update , true ); - } + template + inline typename std::enable_if::value>::type + exec(reference_type update) const { + const TagType t{}; + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i, update, true); } + } -public: - - inline - void execute() const - { - const size_t pool_reduce_size = Analysis::value_size( m_functor ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = Analysis::value_size(m_functor); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - reference_type update = - ValueInit::init( m_functor , pointer_type(data.pool_reduce_local()) ); + reference_type update = + ValueInit::init(m_functor, pointer_type(data.pool_reduce_local())); - this-> template exec< WorkTag >( update ); - } + this->template exec(update); + } - inline - ParallelScan( const FunctorType & arg_functor - , const Policy & arg_policy - ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - {} + inline ParallelScan(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), m_policy(arg_policy) {} }; /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ReturnType, class ... Traits > -class ParallelScanWithTotal< FunctorType - , Kokkos::RangePolicy< Traits ... > - , ReturnType - , Kokkos::Serial - > -{ -private: - - typedef Kokkos::RangePolicy< Traits ... > Policy ; - typedef typename Policy::work_tag WorkTag ; - - typedef FunctorAnalysis< FunctorPatternInterface::SCAN , Policy , FunctorType > Analysis ; - - typedef Kokkos::Impl::FunctorValueInit< FunctorType , WorkTag > ValueInit ; - - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; - - const FunctorType m_functor ; - const Policy m_policy ; - ReturnType & m_returnvalue; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( i , update , true ); - } +template +class ParallelScanWithTotal, + ReturnType, Kokkos::Serial> { + private: + typedef Kokkos::RangePolicy Policy; + typedef typename Policy::work_tag WorkTag; + + typedef FunctorAnalysis + Analysis; + + typedef Kokkos::Impl::FunctorValueInit ValueInit; + + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; + + const FunctorType m_functor; + const Policy m_policy; + ReturnType& m_returnvalue; + + template + inline typename std::enable_if::value>::type exec( + reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(i, update, true); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( reference_type update ) const - { - const TagType t{} ; - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - m_functor( t , i , update , true ); - } + template + inline typename std::enable_if::value>::type + exec(reference_type update) const { + const TagType t{}; + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + m_functor(t, i, update, true); } + } -public: - - inline - void execute() - { - const size_t pool_reduce_size = Analysis::value_size( m_functor ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() { + const size_t pool_reduce_size = Analysis::value_size(m_functor); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - reference_type update = - ValueInit::init( m_functor , pointer_type(data.pool_reduce_local()) ); + reference_type update = + ValueInit::init(m_functor, pointer_type(data.pool_reduce_local())); - this-> template exec< WorkTag >( update ); + this->template exec(update); - m_returnvalue = update; - } + m_returnvalue = update; + } - inline - ParallelScanWithTotal( const FunctorType & arg_functor - , const Policy & arg_policy - , ReturnType & arg_returnvalue - ) - : m_functor( arg_functor ) - , m_policy( arg_policy ) - , m_returnvalue( arg_returnvalue ) - {} + inline ParallelScanWithTotal(const FunctorType& arg_functor, + const Policy& arg_policy, + ReturnType& arg_returnvalue) + : m_functor(arg_functor), + m_policy(arg_policy), + m_returnvalue(arg_returnvalue) {} }; -} // namespace Impl -} // namespace Kokkos - +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -815,169 +805,143 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Traits > -class ParallelFor< FunctorType , - Kokkos::MDRangePolicy< Traits ... > , - Kokkos::Serial - > -{ -private: - - typedef Kokkos::MDRangePolicy< Traits ... > MDRangePolicy ; - typedef typename MDRangePolicy::impl_range_policy Policy ; - - typedef typename Kokkos::Impl::HostIterateTile< MDRangePolicy, FunctorType, typename MDRangePolicy::work_tag, void > iterate_type; - - const FunctorType m_functor ; - const MDRangePolicy m_mdr_policy ; - const Policy m_policy ; - - void - exec() const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - iterate_type( m_mdr_policy, m_functor )( i ); - } +template +class ParallelFor, + Kokkos::Serial> { + private: + typedef Kokkos::MDRangePolicy MDRangePolicy; + typedef typename MDRangePolicy::impl_range_policy Policy; + + typedef typename Kokkos::Impl::HostIterateTile< + MDRangePolicy, FunctorType, typename MDRangePolicy::work_tag, void> + iterate_type; + + const FunctorType m_functor; + const MDRangePolicy m_mdr_policy; + const Policy m_policy; + + void exec() const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + iterate_type(m_mdr_policy, m_functor)(i); } + } -public: - - inline - void execute() const - { this->exec(); } + public: + inline void execute() const { this->exec(); } - inline - ParallelFor( const FunctorType & arg_functor - , const MDRangePolicy & arg_policy ) - : m_functor( arg_functor ) - , m_mdr_policy( arg_policy ) - , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) - {} + inline ParallelFor(const FunctorType& arg_functor, + const MDRangePolicy& arg_policy) + : m_functor(arg_functor), + m_mdr_policy(arg_policy), + m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)) {} }; +template +class ParallelReduce, ReducerType, + Kokkos::Serial> { + private: + typedef Kokkos::MDRangePolicy MDRangePolicy; + typedef typename MDRangePolicy::impl_range_policy Policy; -template< class FunctorType , class ReducerType , class ... Traits > -class ParallelReduce< FunctorType - , Kokkos::MDRangePolicy< Traits ... > - , ReducerType - , Kokkos::Serial - > -{ -private: + typedef typename MDRangePolicy::work_tag WorkTag; - typedef Kokkos::MDRangePolicy< Traits ... > MDRangePolicy ; - typedef typename MDRangePolicy::impl_range_policy Policy ; - - typedef typename MDRangePolicy::work_tag WorkTag ; - - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; - - typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , MDRangePolicy , FunctorType > Analysis ; - - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTagFwd > ValueInit ; - - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::value_type value_type ; - typedef typename Analysis::reference_type reference_type ; - - - using iterate_type = typename Kokkos::Impl::HostIterateTile< MDRangePolicy - , FunctorType - , WorkTag - , reference_type - >; - - - const FunctorType m_functor ; - const MDRangePolicy m_mdr_policy ; - const Policy m_policy ; - const ReducerType m_reducer ; - const pointer_type m_result_ptr ; - - inline - void - exec( reference_type update ) const - { - const typename Policy::member_type e = m_policy.end(); - for ( typename Policy::member_type i = m_policy.begin() ; i < e ; ++i ) { - iterate_type( m_mdr_policy, m_functor, update )( i ); - } + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef FunctorAnalysis + Analysis; + + typedef Kokkos::Impl::FunctorValueInit ValueInit; + + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::value_type value_type; + typedef typename Analysis::reference_type reference_type; + + using iterate_type = + typename Kokkos::Impl::HostIterateTile; + + const FunctorType m_functor; + const MDRangePolicy m_mdr_policy; + const Policy m_policy; + const ReducerType m_reducer; + const pointer_type m_result_ptr; + + inline void exec(reference_type update) const { + const typename Policy::member_type e = m_policy.end(); + for (typename Policy::member_type i = m_policy.begin(); i < e; ++i) { + iterate_type(m_mdr_policy, m_functor, update)(i); } + } -public: - - inline - void execute() const - { - const size_t pool_reduce_size = - Analysis::value_size( ReducerConditional::select(m_functor , m_reducer) ); - const size_t team_reduce_size = 0 ; // Never shrinks - const size_t team_shared_size = 0 ; // Never shrinks - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = + Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); + const size_t team_reduce_size = 0; // Never shrinks + const size_t team_shared_size = 0; // Never shrinks + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - pointer_type ptr = + pointer_type ptr = m_result_ptr ? m_result_ptr : pointer_type(data.pool_reduce_local()); - reference_type update = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , ptr ); + reference_type update = + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), ptr); - this-> exec( update ); + this->exec(update); - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >:: - final( ReducerConditional::select(m_functor , m_reducer) , ptr ); - } + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), ptr); + } - template< class HostViewType > - ParallelReduce( const FunctorType & arg_functor , - const MDRangePolicy & arg_policy , - const HostViewType & arg_result_view , - typename std::enable_if< - Kokkos::is_view< HostViewType >::value && - !Kokkos::is_reducer_type::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_mdr_policy( arg_policy ) - , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result_view.data() ) - { - static_assert( Kokkos::is_view< HostViewType >::value - , "Kokkos::Serial reduce result must be a View" ); - - static_assert( std::is_same< typename HostViewType::memory_space , HostSpace >::value - , "Kokkos::Serial reduce result must be a View in HostSpace" ); - } + template + ParallelReduce( + const FunctorType& arg_functor, const MDRangePolicy& arg_policy, + const HostViewType& arg_result_view, + typename std::enable_if::value && + !Kokkos::is_reducer_type::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_mdr_policy(arg_policy), + m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), + m_reducer(InvalidType()), + m_result_ptr(arg_result_view.data()) { + static_assert(Kokkos::is_view::value, + "Kokkos::Serial reduce result must be a View"); + + static_assert( + std::is_same::value, + "Kokkos::Serial reduce result must be a View in HostSpace"); + } - inline - ParallelReduce( const FunctorType & arg_functor - , MDRangePolicy arg_policy - , const ReducerType& reducer ) - : m_functor( arg_functor ) - , m_mdr_policy( arg_policy ) - , m_policy( Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1) ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - { - /*static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" );*/ - } + inline ParallelReduce(const FunctorType& arg_functor, + MDRangePolicy arg_policy, const ReducerType& reducer) + : m_functor(arg_functor), + m_mdr_policy(arg_policy), + m_policy(Policy(0, m_mdr_policy.m_num_tiles).set_chunk_size(1)), + m_reducer(reducer), + m_result_ptr(reducer.view().data()) { + /*static_assert( std::is_same< typename ViewType::memory_space + , Kokkos::HostSpace >::value + , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" + );*/ + } }; - - -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ @@ -986,225 +950,193 @@ public: namespace Kokkos { namespace Impl { -template< class FunctorType , class ... Properties > -class ParallelFor< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , Kokkos::Serial - > -{ -private: - +template +class ParallelFor, + Kokkos::Serial> { + private: enum { TEAM_REDUCE_SIZE = 512 }; - typedef TeamPolicyInternal< Kokkos::Serial , Properties ...> Policy ; - typedef typename Policy::member_type Member ; - - const FunctorType m_functor ; - const int m_league ; - const int m_shared ; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data ) const - { - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( Member(data,ileague,m_league) ); - } - } + typedef TeamPolicyInternal Policy; + typedef typename Policy::member_type Member; - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data ) const - { - const TagType t{} ; - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( t , Member(data,ileague,m_league) ); - } + const FunctorType m_functor; + const int m_league; + const int m_shared; + + template + inline typename std::enable_if::value>::type exec( + HostThreadTeamData& data) const { + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(Member(data, ileague, m_league)); } + } -public: + template + inline typename std::enable_if::value>::type + exec(HostThreadTeamData& data) const { + const TagType t{}; + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(t, Member(data, ileague, m_league)); + } + } - inline - void execute() const - { - const size_t pool_reduce_size = 0 ; // Never shrinks - const size_t team_reduce_size = TEAM_REDUCE_SIZE ; - const size_t team_shared_size = m_shared ; - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = 0; // Never shrinks + const size_t team_reduce_size = TEAM_REDUCE_SIZE; + const size_t team_shared_size = m_shared; + const size_t thread_local_size = 0; // Never shrinks - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - this->template exec< typename Policy::work_tag >( data ); - } + this->template exec(data); + } - ParallelFor( const FunctorType & arg_functor - , const Policy & arg_policy ) - : m_functor( arg_functor ) - , m_league( arg_policy.league_size() ) - , m_shared( arg_policy.scratch_size(0) + - arg_policy.scratch_size(1) + - FunctorTeamShmemSize< FunctorType >::value( arg_functor , 1 ) ) - { } + ParallelFor(const FunctorType& arg_functor, const Policy& arg_policy) + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + + FunctorTeamShmemSize::value(arg_functor, 1)) {} }; /*--------------------------------------------------------------------------*/ -template< class FunctorType , class ReducerType , class ... Properties > -class ParallelReduce< FunctorType - , Kokkos::TeamPolicy< Properties ... > - , ReducerType - , Kokkos::Serial - > -{ -private: - +template +class ParallelReduce, + ReducerType, Kokkos::Serial> { + private: enum { TEAM_REDUCE_SIZE = 512 }; - typedef TeamPolicyInternal< Kokkos::Serial, Properties ... > Policy ; + typedef TeamPolicyInternal Policy; - typedef FunctorAnalysis< FunctorPatternInterface::REDUCE , Policy , FunctorType > Analysis ; + typedef FunctorAnalysis + Analysis; - typedef typename Policy::member_type Member ; - typedef typename Policy::work_tag WorkTag ; + typedef typename Policy::member_type Member; + typedef typename Policy::work_tag WorkTag; - typedef Kokkos::Impl::if_c< std::is_same::value, FunctorType, ReducerType> ReducerConditional; + typedef Kokkos::Impl::if_c::value, + FunctorType, ReducerType> + ReducerConditional; typedef typename ReducerConditional::type ReducerTypeFwd; - typedef typename Kokkos::Impl::if_c< std::is_same::value, WorkTag, void>::type WorkTagFwd; - - typedef Kokkos::Impl::FunctorValueInit< ReducerTypeFwd , WorkTagFwd > ValueInit ; - - typedef typename Analysis::pointer_type pointer_type ; - typedef typename Analysis::reference_type reference_type ; - - const FunctorType m_functor ; - const int m_league ; - const ReducerType m_reducer ; - pointer_type m_result_ptr ; - const int m_shared ; - - template< class TagType > - inline - typename std::enable_if< std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data , reference_type update ) const - { - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( Member(data,ileague,m_league) , update ); - } + typedef + typename Kokkos::Impl::if_c::value, + WorkTag, void>::type WorkTagFwd; + + typedef Kokkos::Impl::FunctorValueInit ValueInit; + + typedef typename Analysis::pointer_type pointer_type; + typedef typename Analysis::reference_type reference_type; + + const FunctorType m_functor; + const int m_league; + const ReducerType m_reducer; + pointer_type m_result_ptr; + const int m_shared; + + template + inline typename std::enable_if::value>::type exec( + HostThreadTeamData& data, reference_type update) const { + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(Member(data, ileague, m_league), update); } + } - template< class TagType > - inline - typename std::enable_if< ! std::is_same< TagType , void >::value >::type - exec( HostThreadTeamData & data , reference_type update ) const - { - const TagType t{} ; + template + inline typename std::enable_if::value>::type + exec(HostThreadTeamData& data, reference_type update) const { + const TagType t{}; - for ( int ileague = 0 ; ileague < m_league ; ++ileague ) { - m_functor( t , Member(data,ileague,m_league) , update ); - } + for (int ileague = 0; ileague < m_league; ++ileague) { + m_functor(t, Member(data, ileague, m_league), update); } + } -public: - - inline - void execute() const - { - const size_t pool_reduce_size = - Analysis::value_size( ReducerConditional::select(m_functor, m_reducer)); - - const size_t team_reduce_size = TEAM_REDUCE_SIZE ; - const size_t team_shared_size = m_shared ; - const size_t thread_local_size = 0 ; // Never shrinks + public: + inline void execute() const { + const size_t pool_reduce_size = + Analysis::value_size(ReducerConditional::select(m_functor, m_reducer)); - serial_resize_thread_team_data( pool_reduce_size - , team_reduce_size - , team_shared_size - , thread_local_size ); + const size_t team_reduce_size = TEAM_REDUCE_SIZE; + const size_t team_shared_size = m_shared; + const size_t thread_local_size = 0; // Never shrinks + serial_resize_thread_team_data(pool_reduce_size, team_reduce_size, + team_shared_size, thread_local_size); - HostThreadTeamData & data = *serial_get_thread_team_data(); + HostThreadTeamData& data = *serial_get_thread_team_data(); - pointer_type ptr = + pointer_type ptr = m_result_ptr ? m_result_ptr : pointer_type(data.pool_reduce_local()); - reference_type update = - ValueInit::init( ReducerConditional::select(m_functor , m_reducer) , ptr ); + reference_type update = + ValueInit::init(ReducerConditional::select(m_functor, m_reducer), ptr); - this-> template exec< WorkTag >( data , update ); + this->template exec(data, update); - Kokkos::Impl::FunctorFinal< ReducerTypeFwd , WorkTagFwd >:: - final( ReducerConditional::select(m_functor , m_reducer) , ptr ); - } - - template< class ViewType > - ParallelReduce( const FunctorType & arg_functor - , const Policy & arg_policy - , const ViewType & arg_result , - typename std::enable_if< - Kokkos::is_view< ViewType >::value && - !Kokkos::is_reducer_type::value - ,void*>::type = NULL) - : m_functor( arg_functor ) - , m_league( arg_policy.league_size() ) - , m_reducer( InvalidType() ) - , m_result_ptr( arg_result.data() ) - , m_shared( arg_policy.scratch_size(0) + - arg_policy.scratch_size(1) + - FunctorTeamShmemSize< FunctorType >::value( m_functor , 1 ) ) - { - static_assert( Kokkos::is_view< ViewType >::value - , "Reduction result on Kokkos::Serial must be a Kokkos::View" ); - - static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::Serial must be a Kokkos::View in HostSpace" ); - } + Kokkos::Impl::FunctorFinal::final( + ReducerConditional::select(m_functor, m_reducer), ptr); + } - inline - ParallelReduce( const FunctorType & arg_functor - , Policy arg_policy - , const ReducerType& reducer ) - : m_functor( arg_functor ) - , m_league( arg_policy.league_size() ) - , m_reducer( reducer ) - , m_result_ptr( reducer.view().data() ) - , m_shared( arg_policy.scratch_size(0) + - arg_policy.scratch_size(1) + - FunctorTeamShmemSize< FunctorType >::value( arg_functor , 1 ) ) - { - /*static_assert( std::is_same< typename ViewType::memory_space - , Kokkos::HostSpace >::value - , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" );*/ + template + ParallelReduce( + const FunctorType& arg_functor, const Policy& arg_policy, + const ViewType& arg_result, + typename std::enable_if::value && + !Kokkos::is_reducer_type::value, + void*>::type = NULL) + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_reducer(InvalidType()), + m_result_ptr(arg_result.data()), + m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + + FunctorTeamShmemSize::value(m_functor, 1)) { + static_assert(Kokkos::is_view::value, + "Reduction result on Kokkos::Serial must be a Kokkos::View"); + + static_assert( + std::is_same::value, + "Reduction result on Kokkos::Serial must be a Kokkos::View in " + "HostSpace"); } + inline ParallelReduce(const FunctorType& arg_functor, Policy arg_policy, + const ReducerType& reducer) + : m_functor(arg_functor), + m_league(arg_policy.league_size()), + m_reducer(reducer), + m_result_ptr(reducer.view().data()), + m_shared(arg_policy.scratch_size(0) + arg_policy.scratch_size(1) + + FunctorTeamShmemSize::value(arg_functor, 1)) { + /*static_assert( std::is_same< typename ViewType::memory_space + , Kokkos::HostSpace >::value + , "Reduction result on Kokkos::OpenMP must be a Kokkos::View in HostSpace" + );*/ + } }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/ -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { -template<> -class UniqueToken< Serial, UniqueTokenScope::Instance> -{ -public: +template <> +class UniqueToken { + public: using execution_space = Serial; using size_type = int; /// \brief create object size for concurrency on the given instance /// /// This object should not be shared between instances - UniqueToken( execution_space const& = execution_space() ) noexcept {} + UniqueToken(execution_space const& = execution_space()) noexcept {} /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION @@ -1212,24 +1144,23 @@ public: /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - int acquire() const noexcept { return 0; } + int acquire() const noexcept { return 0; } /// \brief release a value acquired by generate KOKKOS_INLINE_FUNCTION - void release( int ) const noexcept {} + void release(int) const noexcept {} }; -template<> -class UniqueToken< Serial, UniqueTokenScope::Global> -{ -public: +template <> +class UniqueToken { + public: using execution_space = Serial; using size_type = int; /// \brief create object size for concurrency on the given instance /// /// This object should not be shared between instances - UniqueToken( execution_space const& = execution_space() ) noexcept {} + UniqueToken(execution_space const& = execution_space()) noexcept {} /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION @@ -1237,17 +1168,17 @@ public: /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - int acquire() const noexcept { return 0; } + int acquire() const noexcept { return 0; } /// \brief release a value acquired by generate KOKKOS_INLINE_FUNCTION - void release( int ) const noexcept {} + void release(int) const noexcept {} }; -}} // namespace Kokkos::Experimental +} // namespace Experimental +} // namespace Kokkos #include -#endif // defined( KOKKOS_ENABLE_SERIAL ) -#endif /* #define KOKKOS_SERIAL_HPP */ - +#endif // defined( KOKKOS_ENABLE_SERIAL ) +#endif /* #define KOKKOS_SERIAL_HPP */ diff --git a/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp b/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp index 00bceec2b5..91e079a0e7 100644 --- a/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskPolicy.hpp @@ -1,13 +1,14 @@ /* //@HEADER // ************************************************************************ -// -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation -// -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). +// +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. -// +// // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -36,7 +37,7 @@ // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // // Questions? Contact Christian R. Trott (crtrott@sandia.gov) -// +// // ************************************************************************ //@HEADER */ @@ -44,4 +45,3 @@ // For backward compatibility: #include - diff --git a/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp b/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp index 1c3d58af08..4a78d6aca1 100644 --- a/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskScheduler.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) #include #include @@ -74,36 +75,33 @@ namespace Impl { template class TaskExec; -} // end namespace Impl - - -template -class BasicTaskScheduler : public Impl::TaskSchedulerBase -{ -public: - - using scheduler_type = BasicTaskScheduler; - using execution_space = ExecSpace; - using queue_type = QueueType; - using memory_space = typename queue_type::memory_space; - using memory_pool = typename queue_type::memory_pool; - using specialization = Impl::TaskQueueSpecialization; - using member_type = typename specialization::member_type; +} // end namespace Impl + +template +class BasicTaskScheduler : public Impl::TaskSchedulerBase { + public: + using scheduler_type = BasicTaskScheduler; + using execution_space = ExecSpace; + using queue_type = QueueType; + using memory_space = typename queue_type::memory_space; + using memory_pool = typename queue_type::memory_pool; + using specialization = Impl::TaskQueueSpecialization; + using member_type = typename specialization::member_type; using team_scheduler_type = BasicTaskScheduler; template - using runnable_task_type = Impl::Task; + using runnable_task_type = + Impl::Task; template using future_type = Kokkos::BasicFuture; template using future_type_for_functor = future_type; -private: - - using track_type = Kokkos::Impl::SharedAllocationTracker ; + private: + using track_type = Kokkos::Impl::SharedAllocationTracker; using task_base = Impl::TaskBase; track_type m_track; - queue_type * m_queue; + queue_type* m_queue; //---------------------------------------- @@ -121,17 +119,12 @@ private: //---------------------------------------- KOKKOS_INLINE_FUNCTION - BasicTaskScheduler( - track_type arg_track, - queue_type* arg_queue - ) - : m_track(std::move(arg_track)), - m_queue(std::move(arg_queue)) - { } + BasicTaskScheduler(track_type arg_track, queue_type* arg_queue) + : m_track(std::move(arg_track)), m_queue(std::move(arg_queue)) {} KOKKOS_INLINE_FUNCTION team_scheduler_type get_team_scheduler(int team_rank) const { - return { m_track, &m_queue->get_team_queue(team_rank) }; + return {m_track, &m_queue->get_team_queue(team_rank)}; } //---------------------------------------- @@ -140,25 +133,23 @@ private: static constexpr task_base* _get_task_ptr(std::nullptr_t) { return nullptr; } template - KOKKOS_INLINE_FUNCTION - static constexpr task_base* _get_task_ptr(future_type&& f) - { + KOKKOS_INLINE_FUNCTION static constexpr task_base* _get_task_ptr( + future_type&& f) { return f.m_task; } - template< int TaskEnum , typename DepTaskType , typename FunctorType > + template KOKKOS_FUNCTION - Kokkos::BasicFuture - _spawn_impl( - DepTaskType* arg_predecessor_task, - TaskPriority arg_priority, - typename task_base::function_type arg_function, - typename task_base::destroy_type arg_destroy, - FunctorType&& arg_functor - ) - { - using functor_future_type = future_type_for_functor::type>; - using task_type = Impl::Task; + Kokkos::BasicFuture + _spawn_impl(DepTaskType* arg_predecessor_task, TaskPriority arg_priority, + typename task_base::function_type arg_function, + typename task_base::destroy_type arg_destroy, + FunctorType&& arg_functor) { + using functor_future_type = + future_type_for_functor::type>; + using task_type = + Impl::Task; //---------------------------------------- // Give single-thread back-ends an opportunity to clear @@ -169,25 +160,25 @@ private: //---------------------------------------- - functor_future_type f ; + functor_future_type f; // Allocate task from memory pool const size_t alloc_size = - m_queue->template spawn_allocation_size< FunctorType >(); + m_queue->template spawn_allocation_size(); void* task_storage = m_queue->allocate(alloc_size); if (task_storage) { - // Placement new construction // Reference count starts at two: // +1 for the matching decrement when task is complete // +1 for the future - f.m_task = new (task_storage) task_type( std::forward(arg_functor) ); + f.m_task = + new (task_storage) task_type(std::forward(arg_functor)); - f.m_task->m_apply = arg_function; - //f.m_task->m_destroy = arg_destroy; + f.m_task->m_apply = arg_function; + // f.m_task->m_destroy = arg_destroy; f.m_task->m_queue = m_queue; f.m_task->m_next = arg_predecessor_task; f.m_task->m_ref_count = 2; @@ -202,81 +193,70 @@ private: // reference count does not need to be incremented for // the assignment. - m_queue->schedule_runnable( f.m_task ); + m_queue->schedule_runnable(f.m_task); // This task may be updated or executed at any moment, // even during the call to 'schedule'. } return f; - } -public: - - + public: KOKKOS_INLINE_FUNCTION BasicTaskScheduler() : m_track(), m_queue(0) {} KOKKOS_INLINE_FUNCTION - BasicTaskScheduler( BasicTaskScheduler && rhs ) noexcept - : m_track(rhs.m_track), // probably should be a move, but this is deprecated code anyway - m_queue(std::move(rhs.m_queue)) - { } + BasicTaskScheduler(BasicTaskScheduler&& rhs) noexcept + : m_track(rhs.m_track), // probably should be a move, but this is + // deprecated code anyway + m_queue(std::move(rhs.m_queue)) {} KOKKOS_INLINE_FUNCTION - BasicTaskScheduler( BasicTaskScheduler const & rhs ) - : m_track(rhs.m_track), - m_queue(rhs.m_queue) - { } + BasicTaskScheduler(BasicTaskScheduler const& rhs) + : m_track(rhs.m_track), m_queue(rhs.m_queue) {} KOKKOS_INLINE_FUNCTION - BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept - { - m_track = rhs.m_track; // probably should be a move, but this is deprecated code anyway + BasicTaskScheduler& operator=(BasicTaskScheduler&& rhs) noexcept { + m_track = rhs.m_track; // probably should be a move, but this is deprecated + // code anyway m_queue = std::move(rhs.m_queue); return *this; } KOKKOS_INLINE_FUNCTION - BasicTaskScheduler& operator=(BasicTaskScheduler const& rhs) - { + BasicTaskScheduler& operator=(BasicTaskScheduler const& rhs) { m_track = rhs.m_track; m_queue = rhs.m_queue; return *this; } - explicit BasicTaskScheduler(memory_pool const & arg_memory_pool) noexcept - : m_track(), m_queue(0) - { - typedef Kokkos::Impl::SharedAllocationRecord - < memory_space , typename queue_type::Destroy > - record_type ; + explicit BasicTaskScheduler(memory_pool const& arg_memory_pool) noexcept + : m_track(), m_queue(0) { + typedef Kokkos::Impl::SharedAllocationRecord + record_type; - record_type * record = - record_type::allocate( memory_space() - , "TaskQueue" - , sizeof(queue_type) - ); + record_type* record = + record_type::allocate(memory_space(), "TaskQueue", sizeof(queue_type)); - m_queue = new( record->data() ) queue_type( arg_memory_pool ); + m_queue = new (record->data()) queue_type(arg_memory_pool); - record->m_destroy.m_queue = m_queue ; + record->m_destroy.m_queue = m_queue; - m_track.assign_allocated_record_to_uninitialized( record ); - } + m_track.assign_allocated_record_to_uninitialized(record); + } - BasicTaskScheduler( memory_space const & arg_memory_space - , size_t const mempool_capacity - , unsigned const mempool_min_block_size // = 1u << 6 - , unsigned const mempool_max_block_size // = 1u << 10 - , unsigned const mempool_superblock_size // = 1u << 12 - ) - : BasicTaskScheduler( memory_pool( arg_memory_space - , mempool_capacity - , mempool_min_block_size - , mempool_max_block_size - , mempool_superblock_size ) ) - {} + BasicTaskScheduler(memory_space const& arg_memory_space, + size_t const mempool_capacity, + unsigned const mempool_min_block_size // = 1u << 6 + , + unsigned const mempool_max_block_size // = 1u << 10 + , + unsigned const mempool_superblock_size // = 1u << 12 + ) + : BasicTaskScheduler(memory_pool( + arg_memory_space, mempool_capacity, mempool_min_block_size, + mempool_max_block_size, mempool_superblock_size)) {} //---------------------------------------- @@ -287,104 +267,89 @@ public: } KOKKOS_INLINE_FUNCTION - memory_pool * memory() const noexcept - { return m_queue ? &( m_queue->m_memory ) : (memory_pool*) 0 ; } + memory_pool* memory() const noexcept { + return m_queue ? &(m_queue->m_memory) : (memory_pool*)0; + } //---------------------------------------- /**\brief Allocation size for a spawned task */ - template< typename FunctorType > - KOKKOS_FUNCTION - size_t spawn_allocation_size() const - { return m_queue->template spawn_allocation_size< FunctorType >(); } + template + KOKKOS_FUNCTION size_t spawn_allocation_size() const { + return m_queue->template spawn_allocation_size(); + } /**\brief Allocation size for a when_all aggregate */ KOKKOS_FUNCTION - size_t when_all_allocation_size( int narg ) const - { return m_queue->when_all_allocation_size( narg ); } - + size_t when_all_allocation_size(int narg) const { + return m_queue->when_all_allocation_size(narg); + } //---------------------------------------- template - KOKKOS_FUNCTION static - Kokkos::BasicFuture - spawn( - Impl::TaskPolicyWithScheduler&& arg_policy, - typename task_base::function_type arg_function, - typename task_base::destroy_type arg_destroy, - FunctorType&& arg_functor - ) - { - return std::move(arg_policy.scheduler()).template _spawn_impl( - _get_task_ptr(std::move(arg_policy.predecessor())), - arg_policy.priority(), - arg_function, - arg_destroy, - std::forward(arg_functor) - ); + KOKKOS_FUNCTION static Kokkos::BasicFuture + spawn(Impl::TaskPolicyWithScheduler&& + arg_policy, + typename task_base::function_type arg_function, + typename task_base::destroy_type arg_destroy, + FunctorType&& arg_functor) { + return std::move(arg_policy.scheduler()) + .template _spawn_impl( + _get_task_ptr(std::move(arg_policy.predecessor())), + arg_policy.priority(), arg_function, arg_destroy, + std::forward(arg_functor)); } template KOKKOS_FUNCTION - future_type_for_functor::type> - spawn( - Impl::TaskPolicyWithPredecessor&& arg_policy, - FunctorType&& arg_functor - ) - { + future_type_for_functor::type> + spawn( + Impl::TaskPolicyWithPredecessor&& arg_policy, + FunctorType&& arg_functor) { using task_type = runnable_task_type; typename task_type::function_type const ptr = task_type::apply; typename task_type::destroy_type const dtor = task_type::destroy; return _spawn_impl( - _get_task_ptr(std::move(arg_policy).predecessor()), - arg_policy.priority(), - ptr, dtor, - std::forward(arg_functor) - ); + _get_task_ptr(std::move(arg_policy).predecessor()), + arg_policy.priority(), ptr, dtor, + std::forward(arg_functor)); } - template - KOKKOS_FUNCTION static - void - respawn( - FunctorType* arg_self, - BasicFuture const & arg_dependence, - TaskPriority const & arg_priority - ) { + template + KOKKOS_FUNCTION static void respawn( + FunctorType* arg_self, + BasicFuture const& arg_dependence, + TaskPriority const& arg_priority) { // Precondition: task is in Executing state - using value_type = typename FunctorType::value_type ; - using task_type = Impl::Task; + using value_type = typename FunctorType::value_type; + using task_type = Impl::Task; - task_type * const task = static_cast< task_type * >( arg_self ); + task_type* const task = static_cast(arg_self); task->m_priority = static_cast(arg_priority); - task->add_dependence( arg_dependence.m_task ); + task->add_dependence(arg_dependence.m_task); // Postcondition: task is in Executing-Respawn state } - template< typename FunctorType > - KOKKOS_FUNCTION static - void - respawn( - FunctorType* arg_self, - BasicTaskScheduler const &, - TaskPriority const & arg_priority - ) - { + template + KOKKOS_FUNCTION static void respawn(FunctorType* arg_self, + BasicTaskScheduler const&, + TaskPriority const& arg_priority) { // Precondition: task is in Executing state using value_type = typename FunctorType::value_type; - using task_type = Impl::Task; + using task_type = Impl::Task; - task_type * const task = static_cast< task_type * >( arg_self ); + task_type* const task = static_cast(arg_self); task->m_priority = static_cast(arg_priority); - task->add_dependence( (task_base*) 0 ); + task->add_dependence((task_base*)0); // Postcondition: task is in Executing-Respawn state } @@ -393,162 +358,153 @@ public: /**\brief Return a future that is complete * when all input futures are complete. */ - template - KOKKOS_FUNCTION - BasicFuture< void, scheduler_type > - when_all(BasicFuture const arg[], int narg) - { - - future_type f ; - - if ( narg ) { + template + KOKKOS_FUNCTION BasicFuture when_all( + BasicFuture const arg[], int narg) { + future_type f; + if (narg) { queue_type* q = m_queue; - //BasicTaskScheduler const* scheduler_ptr = nullptr; + // BasicTaskScheduler const* scheduler_ptr = nullptr; - for ( int i = 0 ; i < narg ; ++i ) { - task_base * const t = arg[i].m_task ; - if ( nullptr != t ) { + for (int i = 0; i < narg; ++i) { + task_base* const t = arg[i].m_task; + if (nullptr != t) { // Increment reference count to track subsequent assignment. - Kokkos::atomic_increment( &(t->m_ref_count) ); - if(q != static_cast< queue_type const* >(t->m_queue)) { - Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" ); + Kokkos::atomic_increment(&(t->m_ref_count)); + if (q != static_cast(t->m_queue)) { + Kokkos::abort( + "Kokkos when_all Futures must be in the same scheduler"); } } } - if ( q != 0 ) { // this should probably handle the queue == 0 case, but this is deprecated code anyway - - size_t const alloc_size = q->when_all_allocation_size( narg ); + if (q != 0) { // this should probably handle the queue == 0 case, but + // this is deprecated code anyway - f.m_task = - reinterpret_cast< task_base * >( q->allocate( alloc_size ) ); - //f.m_scheduler = *scheduler_ptr; + size_t const alloc_size = q->when_all_allocation_size(narg); - if ( f.m_task ) { + f.m_task = reinterpret_cast(q->allocate(alloc_size)); + // f.m_scheduler = *scheduler_ptr; + if (f.m_task) { // Reference count starts at two: // +1 to match decrement when task completes // +1 for the future - new( f.m_task ) task_base(); + new (f.m_task) task_base(); - f.m_task->m_queue = q; - f.m_task->m_ref_count = 2 ; + f.m_task->m_queue = q; + f.m_task->m_ref_count = 2; f.m_task->m_alloc_size = static_cast(alloc_size); - f.m_task->m_dep_count = narg ; - f.m_task->m_task_type = task_base::Aggregate ; + f.m_task->m_dep_count = narg; + f.m_task->m_task_type = task_base::Aggregate; // Assign dependences, reference counts were already incremented - task_base * volatile * const dep = - f.m_task->aggregate_dependences(); + task_base* volatile* const dep = f.m_task->aggregate_dependences(); - for ( int i = 0 ; i < narg ; ++i ) { dep[i] = arg[i].m_task ; } + for (int i = 0; i < narg; ++i) { + dep[i] = arg[i].m_task; + } Kokkos::memory_fence(); - q->schedule_aggregate( f.m_task ); + q->schedule_aggregate(f.m_task); // this when_all may be processed at any moment } } } - return f ; + return f; } - template < class F > - KOKKOS_FUNCTION - BasicFuture< void, scheduler_type > - when_all( int narg , F const func ) - { - using input_type = decltype( func(0) ); + template + KOKKOS_FUNCTION BasicFuture when_all(int narg, + F const func) { + using input_type = decltype(func(0)); - static_assert( is_future< input_type >::value - , "Functor must return a Kokkos::Future" ); + static_assert(is_future::value, + "Functor must return a Kokkos::Future"); - future_type f ; + future_type f; - if ( 0 == narg ) return f ; + if (0 == narg) return f; - size_t const alloc_size = m_queue->when_all_allocation_size( narg ); + size_t const alloc_size = m_queue->when_all_allocation_size(narg); - f.m_task = - reinterpret_cast< task_base * >( m_queue->allocate( alloc_size ) ); - - if ( f.m_task ) { - - // Reference count starts at two: - // +1 to match decrement when task completes - // +1 for the future - - new( f.m_task ) task_base(); - //f.m_scheduler = *this; - - //f.m_task->m_scheduler = &f.m_scheduler; - f.m_task->m_queue = m_queue; - f.m_task->m_ref_count = 2 ; - f.m_task->m_alloc_size = static_cast(alloc_size); - f.m_task->m_dep_count = narg ; - f.m_task->m_task_type = task_base::Aggregate ; - //f.m_task->m_apply = nullptr; - //f.m_task->m_destroy = nullptr; - - // Assign dependences, reference counts were already incremented - - task_base * volatile * const dep = - f.m_task->aggregate_dependences(); - - for ( int i = 0 ; i < narg ; ++i ) { - const input_type arg_f = func(i); - if ( 0 != arg_f.m_task ) { - - // Not scheduled, so task scheduler is not yet set - //if ( m_queue != static_cast< BasicTaskScheduler const * >( arg_f.m_task->m_scheduler )->m_queue ) { - // Kokkos::abort("Kokkos when_all Futures must be in the same scheduler" ); - //} - // Increment reference count to track subsequent assignment. - Kokkos::atomic_increment( &(arg_f.m_task->m_ref_count) ); - dep[i] = arg_f.m_task ; - } - } + f.m_task = reinterpret_cast(m_queue->allocate(alloc_size)); - Kokkos::memory_fence(); + if (f.m_task) { + // Reference count starts at two: + // +1 to match decrement when task completes + // +1 for the future + + new (f.m_task) task_base(); + // f.m_scheduler = *this; - m_queue->schedule_aggregate( f.m_task ); - // this when_all may be processed at any moment + // f.m_task->m_scheduler = &f.m_scheduler; + f.m_task->m_queue = m_queue; + f.m_task->m_ref_count = 2; + f.m_task->m_alloc_size = static_cast(alloc_size); + f.m_task->m_dep_count = narg; + f.m_task->m_task_type = task_base::Aggregate; + // f.m_task->m_apply = nullptr; + // f.m_task->m_destroy = nullptr; + + // Assign dependences, reference counts were already incremented + + task_base* volatile* const dep = f.m_task->aggregate_dependences(); + + for (int i = 0; i < narg; ++i) { + const input_type arg_f = func(i); + if (0 != arg_f.m_task) { + // Not scheduled, so task scheduler is not yet set + // if ( m_queue != static_cast< BasicTaskScheduler const * >( + // arg_f.m_task->m_scheduler )->m_queue ) { + // Kokkos::abort("Kokkos when_all Futures must be in the same + // scheduler" ); + //} + // Increment reference count to track subsequent assignment. + Kokkos::atomic_increment(&(arg_f.m_task->m_ref_count)); + dep[i] = arg_f.m_task; + } } - return f ; + + Kokkos::memory_fence(); + + m_queue->schedule_aggregate(f.m_task); + // this when_all may be processed at any moment } + return f; + } //---------------------------------------- KOKKOS_INLINE_FUNCTION - int allocation_capacity() const noexcept - { return m_queue->m_memory.capacity(); } + int allocation_capacity() const noexcept { + return m_queue->m_memory.capacity(); + } KOKKOS_INLINE_FUNCTION - int allocated_task_count() const noexcept - { return m_queue->m_count_alloc ; } + int allocated_task_count() const noexcept { return m_queue->m_count_alloc; } KOKKOS_INLINE_FUNCTION - int allocated_task_count_max() const noexcept - { return m_queue->m_max_alloc ; } + int allocated_task_count_max() const noexcept { return m_queue->m_max_alloc; } KOKKOS_INLINE_FUNCTION - long allocated_task_count_accum() const noexcept - { return m_queue->m_accum_alloc ; } + long allocated_task_count_accum() const noexcept { + return m_queue->m_accum_alloc; + } //---------------------------------------- - template - friend - void wait(Kokkos::BasicTaskScheduler const&); - + template + friend void wait(Kokkos::BasicTaskScheduler const&); }; -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -559,121 +515,77 @@ namespace Kokkos { // Construct a TaskTeam execution policy template -Impl::TaskPolicyWithPredecessor< - Impl::TaskType::TaskTeam, - Kokkos::BasicFuture -> -KOKKOS_INLINE_FUNCTION -TaskTeam( - Kokkos::BasicFuture arg_future, - TaskPriority arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_future), arg_priority }; +Impl::TaskPolicyWithPredecessor > + KOKKOS_INLINE_FUNCTION + TaskTeam(Kokkos::BasicFuture arg_future, + TaskPriority arg_priority = TaskPriority::Regular) { + return {std::move(arg_future), arg_priority}; } template -Impl::TaskPolicyWithScheduler< - Impl::TaskType::TaskTeam, Scheduler -> -KOKKOS_INLINE_FUNCTION -TaskTeam( - Scheduler arg_scheduler, - typename std::enable_if< - Kokkos::is_scheduler::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_scheduler), arg_priority }; +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION + TaskTeam(Scheduler arg_scheduler, + typename std::enable_if::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + return {std::move(arg_scheduler), arg_priority}; } -template< - class Scheduler, - class PredecessorFuture -> -Impl::TaskPolicyWithScheduler< - Kokkos::Impl::TaskType::TaskTeam, - Scheduler, - PredecessorFuture -> -KOKKOS_INLINE_FUNCTION -TaskTeam( - Scheduler arg_scheduler, - PredecessorFuture arg_future, - typename std::enable_if< - Kokkos::is_scheduler::value - && Kokkos::is_future::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - static_assert( - std::is_same::value, - "Can't create a task policy from a scheduler and a future from a different scheduler" - ); - - return { std::move(arg_scheduler), std::move(arg_future), arg_priority }; +template +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION TaskTeam( + Scheduler arg_scheduler, PredecessorFuture arg_future, + typename std::enable_if::value && + Kokkos::is_future::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + static_assert(std::is_same::value, + "Can't create a task policy from a scheduler and a future from " + "a different scheduler"); + + return {std::move(arg_scheduler), std::move(arg_future), arg_priority}; } // Construct a TaskSingle execution policy template -Impl::TaskPolicyWithPredecessor< - Impl::TaskType::TaskSingle, - Kokkos::BasicFuture -> -KOKKOS_INLINE_FUNCTION -TaskSingle( - Kokkos::BasicFuture arg_future, - TaskPriority arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_future), arg_priority }; +Impl::TaskPolicyWithPredecessor > + KOKKOS_INLINE_FUNCTION + TaskSingle(Kokkos::BasicFuture arg_future, + TaskPriority arg_priority = TaskPriority::Regular) { + return {std::move(arg_future), arg_priority}; } template -Impl::TaskPolicyWithScheduler< - Impl::TaskType::TaskSingle, Scheduler -> -KOKKOS_INLINE_FUNCTION -TaskSingle( - Scheduler arg_scheduler, - typename std::enable_if< - Kokkos::is_scheduler::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - return { std::move(arg_scheduler), arg_priority }; +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION + TaskSingle(Scheduler arg_scheduler, + typename std::enable_if::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + return {std::move(arg_scheduler), arg_priority}; } -template< - class Scheduler, - class PredecessorFuture -> -Impl::TaskPolicyWithScheduler< - Kokkos::Impl::TaskType::TaskSingle, - Scheduler, - PredecessorFuture -> -KOKKOS_INLINE_FUNCTION -TaskSingle( - Scheduler arg_scheduler, - PredecessorFuture arg_future, - typename std::enable_if< - Kokkos::is_scheduler::value - && Kokkos::is_future::value, - TaskPriority - >::type arg_priority = TaskPriority::Regular -) -{ - static_assert( - std::is_same::value, - "Can't create a task policy from a scheduler and a future from a different scheduler" - ); - - return { std::move(arg_scheduler), std::move(arg_future), arg_priority }; +template +Impl::TaskPolicyWithScheduler + KOKKOS_INLINE_FUNCTION TaskSingle( + Scheduler arg_scheduler, PredecessorFuture arg_future, + typename std::enable_if::value && + Kokkos::is_future::value, + TaskPriority>::type arg_priority = + TaskPriority::Regular) { + static_assert(std::is_same::value, + "Can't create a task policy from a scheduler and a future from " + "a different scheduler"); + + return {std::move(arg_scheduler), std::move(arg_future), arg_priority}; } //---------------------------------------------------------------------------- @@ -684,31 +596,30 @@ TaskSingle( * 2) With scheduler or dependence * 3) High, Normal, or Low priority */ -template -typename Scheduler::template future_type_for_functor::type> -host_spawn( - Impl::TaskPolicyWithScheduler arg_policy, - FunctorType&& arg_functor -) { +template +typename Scheduler::template future_type_for_functor< + typename std::decay::type> +host_spawn(Impl::TaskPolicyWithScheduler + arg_policy, + FunctorType&& arg_functor) { using scheduler_type = Scheduler; using task_type = - typename scheduler_type::template runnable_task_type; + typename scheduler_type::template runnable_task_type; - static_assert( - TaskEnum == Impl::TaskType::TaskTeam || TaskEnum == Impl::TaskType::TaskSingle, - "Kokkos host_spawn requires TaskTeam or TaskSingle" - ); + static_assert(TaskEnum == Impl::TaskType::TaskTeam || + TaskEnum == Impl::TaskType::TaskSingle, + "Kokkos host_spawn requires TaskTeam or TaskSingle"); // May be spawning a Cuda task, must use the specialization // to query on-device function pointer. typename task_type::function_type ptr; typename task_type::destroy_type dtor; - Kokkos::Impl::TaskQueueSpecialization< scheduler_type >:: - template get_function_pointer< task_type >(ptr, dtor); + Kokkos::Impl::TaskQueueSpecialization< + scheduler_type>::template get_function_pointer(ptr, dtor); - return scheduler_type::spawn( - std::move(arg_policy), ptr, dtor, std::forward(arg_functor) - ); + return scheduler_type::spawn(std::move(arg_policy), ptr, dtor, + std::forward(arg_functor)); } /**\brief A task spawns a task with options @@ -717,38 +628,38 @@ host_spawn( * 2) With scheduler or dependence * 3) High, Normal, or Low priority */ -template -typename Scheduler::template future_type_for_functor::type> -KOKKOS_INLINE_FUNCTION -task_spawn( - Impl::TaskPolicyWithScheduler arg_policy, - FunctorType&& arg_functor -) -{ +template +typename Scheduler::template future_type_for_functor< + typename std::decay::type> + KOKKOS_INLINE_FUNCTION + task_spawn(Impl::TaskPolicyWithScheduler + arg_policy, + FunctorType&& arg_functor) { using scheduler_type = Scheduler; using task_type = - typename scheduler_type::template runnable_task_type; + typename scheduler_type::template runnable_task_type; - #if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) && \ - defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) && \ + defined(KOKKOS_ENABLE_CUDA) - static_assert( ! std::is_same< Kokkos::Cuda , typename Scheduler::execution_space >::value - , "Error calling Kokkos::task_spawn for Cuda space within Host code" ); + // This doesn't work with clang cuda + // static_assert( + // !std::is_same::value, + // "Error calling Kokkos::task_spawn for Cuda space within Host code"); - #endif +#endif - static_assert( - TaskEnum == Impl::TaskType::TaskTeam || TaskEnum == Impl::TaskType::TaskSingle, - "Kokkos task_spawn requires TaskTeam or TaskSingle" - ); + static_assert(TaskEnum == Impl::TaskType::TaskTeam || + TaskEnum == Impl::TaskType::TaskSingle, + "Kokkos task_spawn requires TaskTeam or TaskSingle"); - typename task_type::function_type const ptr = task_type::apply ; - typename task_type::destroy_type const dtor = task_type::destroy ; + typename task_type::function_type const ptr = task_type::apply; + typename task_type::destroy_type const dtor = task_type::destroy; return scheduler_type::spawn(std::move(arg_policy), ptr, dtor, - std::forward(arg_functor) - ); + std::forward(arg_functor)); } /**\brief A task respawns itself with options @@ -756,29 +667,22 @@ task_spawn( * 1) With scheduler or dependence * 2) High, Normal, or Low priority */ -template< typename FunctorType , typename T > -void -KOKKOS_INLINE_FUNCTION -respawn( FunctorType * arg_self - , T const & arg - , TaskPriority const & arg_priority = TaskPriority::Regular - ) -{ - static_assert( Kokkos::is_future::value || - Kokkos::is_scheduler::value - , "Kokkos respawn argument must be Future or TaskScheduler" ); - - T::scheduler_type::respawn( - arg_self , arg , arg_priority - ); +template +void KOKKOS_INLINE_FUNCTION +respawn(FunctorType* arg_self, T const& arg, + TaskPriority const& arg_priority = TaskPriority::Regular) { + static_assert(Kokkos::is_future::value || Kokkos::is_scheduler::value, + "Kokkos respawn argument must be Future or TaskScheduler"); + + T::scheduler_type::respawn(arg_self, arg, arg_priority); } //---------------------------------------------------------------------------- -//template -//KOKKOS_INLINE_FUNCTION -//BasicFuture -//when_all(BasicFuture const arg[], int narg) +// template +// KOKKOS_INLINE_FUNCTION +// BasicFuture +// when_all(BasicFuture const arg[], int narg) //{ // return BasicFuture::scheduler_type::when_all(arg, narg); //} @@ -786,16 +690,14 @@ respawn( FunctorType * arg_self //---------------------------------------------------------------------------- // Wait for all runnable tasks to complete -template -inline -void wait(BasicTaskScheduler const& scheduler) -{ +template +inline void wait(BasicTaskScheduler const& scheduler) { using scheduler_type = BasicTaskScheduler; scheduler_type::specialization::execute(scheduler); - //scheduler.m_queue->execute(); + // scheduler.m_queue->execute(); } -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -806,4 +708,3 @@ void wait(BasicTaskScheduler const& scheduler) #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */ #endif /* #ifndef KOKKOS_TASKSCHEDULER_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp b/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp index 79d502c729..c5f880775d 100644 --- a/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp +++ b/lib/kokkos/core/src/Kokkos_TaskScheduler_fwd.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -47,7 +48,7 @@ //---------------------------------------------------------------------------- #include -#if defined( KOKKOS_ENABLE_TASKDAG ) +#if defined(KOKKOS_ENABLE_TASKDAG) #include //---------------------------------------------------------------------------- @@ -65,22 +66,20 @@ class SimpleTaskScheduler; template class BasicTaskScheduler; -template< typename Space > +template struct is_scheduler : public std::false_type {}; -template -struct is_scheduler> : public std::true_type {}; - -template -struct is_scheduler> : public std::true_type {}; +template +struct is_scheduler> : public std::true_type { +}; -enum class TaskPriority : int { - High = 0, - Regular = 1, - Low = 2 +template +struct is_scheduler> : public std::true_type { }; -} // namespace Kokkos +enum class TaskPriority : int { High = 0, Regular = 1, Low = 2 }; + +} // namespace Kokkos //---------------------------------------------------------------------------- @@ -110,140 +109,124 @@ class TaskBase; * : TaskBase< Space , void , void > * { ... }; */ -template< typename Space , typename ResultType , typename FunctorType > +template class Task; class TaskQueueBase; -template< typename Space, typename MemorySpace> +template class TaskQueue; -template< typename ExecSpace, typename MemorySpace> +template class TaskQueueMultiple; -template< - typename ExecSpace, typename MemSpace, typename TaskQueueTraits, - class MemoryPool = Kokkos::MemoryPool> -> +template >> class SingleTaskQueue; -template< typename ExecSpace, typename MemSpace, typename TaskQueueTraits, class MemoryPool> +template class MultipleTaskQueue; struct TaskQueueTraitsLockBased; -template +template struct TaskQueueTraitsChaseLev; -template< typename ResultType > +template struct TaskResult; struct TaskSchedulerBase; template -struct default_tasking_memory_space_for_execution_space -{ +struct default_tasking_memory_space_for_execution_space { using type = typename ExecSpace::memory_space; }; -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) template <> -struct default_tasking_memory_space_for_execution_space -{ +struct default_tasking_memory_space_for_execution_space { using type = Kokkos::CudaUVMSpace; }; #endif template using default_tasking_memory_space_for_execution_space_t = - typename default_tasking_memory_space_for_execution_space::type; + typename default_tasking_memory_space_for_execution_space::type; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos //---------------------------------------------------------------------------- namespace Kokkos { -template< typename Space > +template using DeprecatedTaskScheduler = BasicTaskScheduler< - Space, - Impl::TaskQueue> ->; + Space, + Impl::TaskQueue< + Space, + Impl::default_tasking_memory_space_for_execution_space_t>>; -template< typename Space > +template using DeprecatedTaskSchedulerMultiple = BasicTaskScheduler< - Space, - Impl::TaskQueueMultiple> ->; + Space, + Impl::TaskQueueMultiple< + Space, + Impl::default_tasking_memory_space_for_execution_space_t>>; -template< typename Space > +template using TaskScheduler = SimpleTaskScheduler< - Space, - Impl::SingleTaskQueue< Space, - Impl::default_tasking_memory_space_for_execution_space_t, - Impl::TaskQueueTraitsLockBased - > ->; + Impl::SingleTaskQueue< + Space, Impl::default_tasking_memory_space_for_execution_space_t, + Impl::TaskQueueTraitsLockBased>>; -template< typename Space > +template using TaskSchedulerMultiple = SimpleTaskScheduler< - Space, - Impl::MultipleTaskQueue< Space, - Impl::default_tasking_memory_space_for_execution_space_t, - Impl::TaskQueueTraitsLockBased, - Kokkos::MemoryPool< - Kokkos::Device< - Space, - Impl::default_tasking_memory_space_for_execution_space_t - > - > - > ->; - -template< typename Space > + Impl::MultipleTaskQueue< + Space, Impl::default_tasking_memory_space_for_execution_space_t, + Impl::TaskQueueTraitsLockBased, + Kokkos::MemoryPool>>>>; + +template using ChaseLevTaskScheduler = SimpleTaskScheduler< - Space, - Impl::MultipleTaskQueue< Space, - Impl::default_tasking_memory_space_for_execution_space_t, - Impl::TaskQueueTraitsChaseLev<>, - Kokkos::MemoryPool< - Kokkos::Device< - Space, - Impl::default_tasking_memory_space_for_execution_space_t - > - > - > ->; - -template + Impl::MultipleTaskQueue< + Space, Impl::default_tasking_memory_space_for_execution_space_t, + Impl::TaskQueueTraitsChaseLev<>, + Kokkos::MemoryPool>>>>; + +template void wait(BasicTaskScheduler const&); namespace Impl { -struct TaskSchedulerBase { }; +struct TaskSchedulerBase {}; -class TaskQueueBase { }; +class TaskQueueBase {}; -template -class TaskQueueSpecializationConstrained { }; +template +class TaskQueueSpecializationConstrained {}; template -struct TaskQueueSpecialization : TaskQueueSpecializationConstrained { }; +struct TaskQueueSpecialization : TaskQueueSpecializationConstrained { +}; template struct TaskPolicyData; +} // end namespace Impl -} // end namespace Impl - -} // namespace Kokkos +} // namespace Kokkos //---------------------------------------------------------------------------- #endif /* #if defined( KOKKOS_ENABLE_TASKDAG ) */ #endif /* #ifndef KOKKOS_TASKSCHEDULER_FWD_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Threads.hpp b/lib/kokkos/core/src/Kokkos_Threads.hpp index 03dab1acaf..d44042b062 100644 --- a/lib/kokkos/core/src/Kokkos_Threads.hpp +++ b/lib/kokkos/core/src/Kokkos_Threads.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -45,7 +46,7 @@ #define KOKKOS_THREADS_HPP #include -#if defined( KOKKOS_ENABLE_THREADS ) +#if defined(KOKKOS_ENABLE_THREADS) #include @@ -61,9 +62,9 @@ namespace Kokkos { namespace Impl { -class ThreadsExec ; -} // namespace Impl -} // namespace Kokkos +class ThreadsExec; +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -71,21 +72,20 @@ namespace Kokkos { /** \brief Execution space for a pool of Pthreads or C11 threads on a CPU. */ class Threads { -public: + public: //! \name Type declarations that all Kokkos devices must provide. //@{ //! Tag this class as a kokkos execution space - typedef Threads execution_space ; - typedef Kokkos::HostSpace memory_space ; + typedef Threads execution_space; + typedef Kokkos::HostSpace memory_space; //! This execution space preferred device_type - typedef Kokkos::Device device_type; + typedef Kokkos::Device device_type; - typedef Kokkos::LayoutRight array_layout ; - typedef memory_space::size_type size_type ; - - typedef ScratchMemorySpace< Threads > scratch_memory_space ; + typedef Kokkos::LayoutRight array_layout; + typedef memory_space::size_type size_type; + typedef ScratchMemorySpace scratch_memory_space; //@} /*------------------------------------------------------------------------*/ @@ -97,7 +97,7 @@ public: static int in_parallel(); /// \brief Print configuration information to the given output stream. - static void print_configuration( std::ostream & , const bool detail = false ); + static void print_configuration(std::ostream&, const bool detail = false); /// \brief Wait until all dispatched functors complete. /// @@ -107,11 +107,11 @@ public: /// device have completed. static void impl_static_fence(); - #ifdef KOKKOS_ENABLE_DEPRECATED_CODE +#ifdef KOKKOS_ENABLE_DEPRECATED_CODE static void fence(); - #else +#else void fence() const; - #endif +#endif /** \brief Return the maximum amount of concurrency. */ static int concurrency(); @@ -123,26 +123,28 @@ public: static void finalize(); - static void initialize( unsigned threads_count = 0 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 , - bool allow_asynchronous_threadpool = false ); + static void initialize(unsigned threads_count = 0, + unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0, + bool allow_asynchronous_threadpool = false); static int is_initialized(); - static Threads & instance( int = 0 ); + static Threads& instance(int = 0); //---------------------------------------- - static int thread_pool_size( int depth = 0 ); -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + static int thread_pool_size(int depth = 0); +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) static int thread_pool_rank(); #else - KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0 ; } + KOKKOS_INLINE_FUNCTION static int thread_pool_rank() { return 0; } #endif inline static unsigned max_hardware_threads() { return thread_pool_size(0); } - KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { return thread_pool_rank(); } + KOKKOS_INLINE_FUNCTION static unsigned hardware_thread_id() { + return thread_pool_rank(); + } #else /// \brief Free any resources being consumed by the device. /// @@ -172,26 +174,30 @@ public: * If the 'use_' arguments are not supplied the hwloc is queried * to use all available cores. */ - static void impl_initialize( unsigned threads_count = 0 , - unsigned use_numa_count = 0 , - unsigned use_cores_per_numa = 0 , - bool allow_asynchronous_threadpool = false ); + static void impl_initialize(unsigned threads_count = 0, + unsigned use_numa_count = 0, + unsigned use_cores_per_numa = 0, + bool allow_asynchronous_threadpool = false); static int impl_is_initialized(); - static Threads & impl_instance( int = 0 ); + static Threads& impl_instance(int = 0); //---------------------------------------- - static int impl_thread_pool_size( int depth = 0 ); -#if defined( KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST ) + static int impl_thread_pool_size(int depth = 0); +#if defined(KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST) static int impl_thread_pool_rank(); #else - KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0 ; } + KOKKOS_INLINE_FUNCTION static int impl_thread_pool_rank() { return 0; } #endif - inline static unsigned impl_max_hardware_threads() { return impl_thread_pool_size(0); } - KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { return impl_thread_pool_rank(); } + inline static unsigned impl_max_hardware_threads() { + return impl_thread_pool_size(0); + } + KOKKOS_INLINE_FUNCTION static unsigned impl_hardware_thread_id() { + return impl_thread_pool_rank(); + } #endif static const char* name(); @@ -199,37 +205,31 @@ public: //---------------------------------------- }; -} // namespace Kokkos +} // namespace Kokkos /*--------------------------------------------------------------------------*/ namespace Kokkos { namespace Impl { -template<> -struct MemorySpaceAccess - < Kokkos::Threads::memory_space - , Kokkos::Threads::scratch_memory_space - > -{ +template <> +struct MemorySpaceAccess { enum { assignable = false }; enum { accessible = true }; - enum { deepcopy = false }; + enum { deepcopy = false }; }; -template<> -struct VerifyExecutionCanAccessMemorySpace - < Kokkos::Threads::memory_space - , Kokkos::Threads::scratch_memory_space - > -{ +template <> +struct VerifyExecutionCanAccessMemorySpace< + Kokkos::Threads::memory_space, Kokkos::Threads::scratch_memory_space> { enum { value = true }; - inline static void verify( void ) { } - inline static void verify( const void * ) { } + inline static void verify(void) {} + inline static void verify(const void*) {} }; -} // namespace Impl -} // namespace Kokkos +} // namespace Impl +} // namespace Kokkos /*--------------------------------------------------------------------------*/ @@ -246,4 +246,3 @@ struct VerifyExecutionCanAccessMemorySpace #endif /* #if defined( KOKKOS_ENABLE_THREADS ) */ #endif /* #define KOKKOS_THREADS_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_Timer.hpp b/lib/kokkos/core/src/Kokkos_Timer.hpp index eb869fd1b0..117f097f66 100644 --- a/lib/kokkos/core/src/Kokkos_Timer.hpp +++ b/lib/kokkos/core/src/Kokkos_Timer.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -51,33 +52,27 @@ namespace Kokkos { /** \brief Time since construction */ class Timer { -private: + private: std::chrono::high_resolution_clock::time_point m_old; - Timer( const Timer & ); - Timer & operator = ( const Timer & ); -public: + Timer(const Timer&); + Timer& operator=(const Timer&); - inline - void reset() { - m_old = std::chrono::high_resolution_clock::now(); - } + public: + inline void reset() { m_old = std::chrono::high_resolution_clock::now(); } - inline - ~Timer() {} + inline ~Timer() {} - inline - Timer() { reset(); } + inline Timer() { reset(); } - inline - double seconds() const - { + inline double seconds() const { std::chrono::high_resolution_clock::time_point m_new = std::chrono::high_resolution_clock::now(); - return std::chrono::duration_cast>(m_new - m_old).count(); + return std::chrono::duration_cast>(m_new - + m_old) + .count(); } }; -} // namespace Kokkos +} // namespace Kokkos #endif /* #ifndef KOKKOS_TIMER_HPP */ - diff --git a/lib/kokkos/core/src/Kokkos_UniqueToken.hpp b/lib/kokkos/core/src/Kokkos_UniqueToken.hpp index d89542631d..523ccad948 100644 --- a/lib/kokkos/core/src/Kokkos_UniqueToken.hpp +++ b/lib/kokkos/core/src/Kokkos_UniqueToken.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,43 +47,42 @@ #include -namespace Kokkos { namespace Experimental { +namespace Kokkos { +namespace Experimental { -enum class UniqueTokenScope : int -{ - Instance, - Global -}; +enum class UniqueTokenScope : int { Instance, Global }; -/// \brief class to generate unique ids base on the required amount of concurrency +/// \brief class to generate unique ids base on the required amount of +/// concurrency /// /// This object should behave like a ref-counted object, so that when the last /// instance is destroy resources are free if needed -template -class UniqueToken -{ -public: +template +class UniqueToken { + public: using execution_space = ExecutionSpace; using size_type = typename execution_space::size_type; /// \brief create object size for concurrency on the given instance /// /// This object should not be shared between instances - UniqueToken( execution_space const& = execution_space() ); + UniqueToken(execution_space const& = execution_space()); /// \brief upper bound for acquired values, i.e. 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type size() const ; + size_type size() const; /// \brief acquire value such that 0 <= value < size() KOKKOS_INLINE_FUNCTION - size_type acquire() const ; + size_type acquire() const; /// \brief release a value acquired by generate KOKKOS_INLINE_FUNCTION - void release( size_type ) const ; + void release(size_type) const; }; -}} // namespace Kokkos::Experimental +} // namespace Experimental +} // namespace Kokkos -#endif //KOKKOS_UNIQUE_TOKEN_HPP +#endif // KOKKOS_UNIQUE_TOKEN_HPP diff --git a/lib/kokkos/core/src/Kokkos_Vectorization.hpp b/lib/kokkos/core/src/Kokkos_Vectorization.hpp index f5b6cad4b7..2604538b1c 100644 --- a/lib/kokkos/core/src/Kokkos_Vectorization.hpp +++ b/lib/kokkos/core/src/Kokkos_Vectorization.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -46,9 +47,8 @@ #ifndef KOKKOS_VECTORIZATION_HPP #define KOKKOS_VECTORIZATION_HPP -#if defined( KOKKOS_ENABLE_CUDA ) +#if defined(KOKKOS_ENABLE_CUDA) #include #endif #endif - diff --git a/lib/kokkos/core/src/Kokkos_View.hpp b/lib/kokkos/core/src/Kokkos_View.hpp index 3fe8e6f067..6610bb842b 100644 --- a/lib/kokkos/core/src/Kokkos_View.hpp +++ b/lib/kokkos/core/src/Kokkos_View.hpp @@ -2,10 +2,11 @@ //@HEADER // ************************************************************************ // -// Kokkos v. 2.0 -// Copyright (2014) Sandia Corporation +// Kokkos v. 3.0 +// Copyright (2020) National Technology & Engineering +// Solutions of Sandia, LLC (NTESS). // -// Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, +// Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Redistribution and use in source and binary forms, with or without @@ -23,10 +24,10 @@ // contributors may be used to endorse or promote products derived from // this software without specific prior written permission. // -// THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY +// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -64,122 +65,88 @@ namespace Kokkos { namespace Impl { -template< class DataType > -struct ViewArrayAnalysis ; +template +struct ViewArrayAnalysis; -template< class DataType , class ArrayLayout - , typename ValueType = - typename ViewArrayAnalysis< DataType >::non_const_value_type - > -struct ViewDataAnalysis ; +template ::non_const_value_type> +struct ViewDataAnalysis; -template< class , class ... > +template class ViewMapping { - public: + public: enum { is_assignable_data_type = false }; enum { is_assignable = false }; }; - - template -KOKKOS_INLINE_FUNCTION -std::size_t count_valid_integers(const IntType i0, - const IntType i1, - const IntType i2, - const IntType i3, - const IntType i4, - const IntType i5, - const IntType i6, - const IntType i7 ){ - static_assert(std::is_integral::value, "count_valid_integers() must have integer arguments."); - - return ( i0 !=KOKKOS_INVALID_INDEX ) + ( i1 !=KOKKOS_INVALID_INDEX ) + ( i2 !=KOKKOS_INVALID_INDEX ) + - ( i3 !=KOKKOS_INVALID_INDEX ) + ( i4 !=KOKKOS_INVALID_INDEX ) + ( i5 !=KOKKOS_INVALID_INDEX ) + - ( i6 !=KOKKOS_INVALID_INDEX ) + ( i7 !=KOKKOS_INVALID_INDEX ); - - +KOKKOS_INLINE_FUNCTION std::size_t count_valid_integers( + const IntType i0, const IntType i1, const IntType i2, const IntType i3, + const IntType i4, const IntType i5, const IntType i6, const IntType i7) { + static_assert(std::is_integral::value, + "count_valid_integers() must have integer arguments."); + + return (i0 != KOKKOS_INVALID_INDEX) + (i1 != KOKKOS_INVALID_INDEX) + + (i2 != KOKKOS_INVALID_INDEX) + (i3 != KOKKOS_INVALID_INDEX) + + (i4 != KOKKOS_INVALID_INDEX) + (i5 != KOKKOS_INVALID_INDEX) + + (i6 != KOKKOS_INVALID_INDEX) + (i7 != KOKKOS_INVALID_INDEX); } #ifndef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION -void runtime_check_rank_device(const size_t dyn_rank, - const bool is_void_spec, - const size_t i0, - const size_t i1, - const size_t i2, - const size_t i3, - const size_t i4, - const size_t i5, - const size_t i6, - const size_t i7 ){ - - if ( is_void_spec ) { - const size_t num_passed_args = count_valid_integers(i0, i1, i2, i3, - i4, i5, i6, i7); - - if ( num_passed_args != dyn_rank && is_void_spec ) { - - Kokkos::abort("Number of arguments passed to Kokkos::View() constructor must match the dynamic rank of the view.") ; - +void runtime_check_rank_device(const size_t dyn_rank, const bool is_void_spec, + const size_t i0, const size_t i1, + const size_t i2, const size_t i3, + const size_t i4, const size_t i5, + const size_t i6, const size_t i7) { + if (is_void_spec) { + const size_t num_passed_args = + count_valid_integers(i0, i1, i2, i3, i4, i5, i6, i7); + + if (num_passed_args != dyn_rank && is_void_spec) { + Kokkos::abort( + "Number of arguments passed to Kokkos::View() constructor must match " + "the dynamic rank of the view."); } } } #else KOKKOS_INLINE_FUNCTION -void runtime_check_rank_device(const size_t , - const bool , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t ){ - -} +void runtime_check_rank_device(const size_t, const bool, const size_t, + const size_t, const size_t, const size_t, + const size_t, const size_t, const size_t, + const size_t) {} #endif #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST #ifndef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION -void runtime_check_rank_host(const size_t dyn_rank, - const bool is_void_spec, - const size_t i0, - const size_t i1, - const size_t i2, - const size_t i3, - const size_t i4, - const size_t i5, - const size_t i6, - const size_t i7, const std::string & label ){ - - - if ( is_void_spec ) { - const size_t num_passed_args = count_valid_integers(i0, i1, i2, i3, - i4, i5, i6, i7); - - if ( num_passed_args != dyn_rank ) { - - const std::string message = "Constructor for Kokkos View '" + label + "' has mismatched number of arguments. Number of arguments = " - + std::to_string(num_passed_args) + " but dynamic rank = " + std::to_string(dyn_rank) + " \n"; - Kokkos::abort(message.c_str()) ; +void runtime_check_rank_host(const size_t dyn_rank, const bool is_void_spec, + const size_t i0, const size_t i1, const size_t i2, + const size_t i3, const size_t i4, const size_t i5, + const size_t i6, const size_t i7, + const std::string& label) { + if (is_void_spec) { + const size_t num_passed_args = + count_valid_integers(i0, i1, i2, i3, i4, i5, i6, i7); + + if (num_passed_args != dyn_rank) { + const std::string message = + "Constructor for Kokkos View '" + label + + "' has mismatched number of arguments. Number of arguments = " + + std::to_string(num_passed_args) + + " but dynamic rank = " + std::to_string(dyn_rank) + " \n"; + Kokkos::abort(message.c_str()); } } } #else KOKKOS_INLINE_FUNCTION -void runtime_check_rank_host(const size_t , - const bool , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , - const size_t , const std::string &){} +void runtime_check_rank_host(const size_t, const bool, const size_t, + const size_t, const size_t, const size_t, + const size_t, const size_t, const size_t, + const size_t, const std::string&) {} #endif #endif @@ -189,10 +156,10 @@ void runtime_check_rank_host(const size_t , // Class to provide a uniform type namespace Kokkos { namespace Impl { - template< class ViewType , int Traits = 0 > - struct ViewUniformType; -} +template +struct ViewUniformType; } +} // namespace Kokkos //---------------------------------------------------------------------------- //---------------------------------------------------------------------------- @@ -216,183 +183,183 @@ namespace Kokkos { * - View< DataType , MemoryTraits > */ -template< class DataType , class ... Properties > -struct ViewTraits ; - -template<> -struct ViewTraits< void > -{ - typedef void execution_space ; - typedef void memory_space ; - typedef void HostMirrorSpace ; - typedef void array_layout ; - typedef void memory_traits ; - typedef void specialize ; +template +struct ViewTraits; + +template <> +struct ViewTraits { + typedef void execution_space; + typedef void memory_space; + typedef void HostMirrorSpace; + typedef void array_layout; + typedef void memory_traits; + typedef void specialize; }; -template< class ... Prop > -struct ViewTraits< void , void , Prop ... > -{ +template +struct ViewTraits { // Ignore an extraneous 'void' - typedef typename ViewTraits::execution_space execution_space ; - typedef typename ViewTraits::memory_space memory_space ; - typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace ; - typedef typename ViewTraits::array_layout array_layout ; - typedef typename ViewTraits::memory_traits memory_traits ; - typedef typename ViewTraits::specialize specialize ; + typedef typename ViewTraits::execution_space execution_space; + typedef typename ViewTraits::memory_space memory_space; + typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace; + typedef typename ViewTraits::array_layout array_layout; + typedef typename ViewTraits::memory_traits memory_traits; + typedef typename ViewTraits::specialize specialize; }; -template< class ArrayLayout , class ... Prop > -struct ViewTraits< typename std::enable_if< Kokkos::Impl::is_array_layout::value >::type , ArrayLayout , Prop ... > -{ +template +struct ViewTraits::value>::type, + ArrayLayout, Prop...> { // Specify layout, keep subsequent space and memory traits arguments - typedef typename ViewTraits::execution_space execution_space ; - typedef typename ViewTraits::memory_space memory_space ; - typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace ; - typedef ArrayLayout array_layout ; - typedef typename ViewTraits::memory_traits memory_traits ; - typedef typename ViewTraits::specialize specialize ; + typedef typename ViewTraits::execution_space execution_space; + typedef typename ViewTraits::memory_space memory_space; + typedef typename ViewTraits::HostMirrorSpace HostMirrorSpace; + typedef ArrayLayout array_layout; + typedef typename ViewTraits::memory_traits memory_traits; + typedef typename ViewTraits::specialize specialize; }; -template< class Space , class ... Prop > -struct ViewTraits< typename std::enable_if< Kokkos::Impl::is_space::value >::type , Space , Prop ... > -{ +template +struct ViewTraits< + typename std::enable_if::value>::type, Space, + Prop...> { // Specify Space, memory traits should be the only subsequent argument. - static_assert( std::is_same< typename ViewTraits::execution_space , void >::value && - std::is_same< typename ViewTraits::memory_space , void >::value && - std::is_same< typename ViewTraits::HostMirrorSpace , void >::value && - std::is_same< typename ViewTraits::array_layout , void >::value - , "Only one View Execution or Memory Space template argument" ); - - typedef typename Space::execution_space execution_space ; - typedef typename Space::memory_space memory_space ; - typedef typename Kokkos::Impl::HostMirror< Space >::Space HostMirrorSpace ; - typedef typename execution_space::array_layout array_layout ; - typedef typename ViewTraits::memory_traits memory_traits ; - typedef typename ViewTraits::specialize specialize ; + static_assert( + std::is_same::execution_space, + void>::value && + std::is_same::memory_space, + void>::value && + std::is_same::HostMirrorSpace, + void>::value && + std::is_same::array_layout, + void>::value, + "Only one View Execution or Memory Space template argument"); + + typedef typename Space::execution_space execution_space; + typedef typename Space::memory_space memory_space; + typedef typename Kokkos::Impl::HostMirror::Space::memory_space + HostMirrorSpace; + typedef typename execution_space::array_layout array_layout; + typedef typename ViewTraits::memory_traits memory_traits; + typedef typename ViewTraits::specialize specialize; }; -template< class MemoryTraits , class ... Prop > -struct ViewTraits< typename std::enable_if< Kokkos::Impl::is_memory_traits::value >::type , MemoryTraits , Prop ... > -{ +template +struct ViewTraits::value>::type, + MemoryTraits, Prop...> { // Specify memory trait, should not be any subsequent arguments - static_assert( std::is_same< typename ViewTraits::execution_space , void >::value && - std::is_same< typename ViewTraits::memory_space , void >::value && - std::is_same< typename ViewTraits::array_layout , void >::value && - std::is_same< typename ViewTraits::memory_traits , void >::value - , "MemoryTrait is the final optional template argument for a View" ); - - typedef void execution_space ; - typedef void memory_space ; - typedef void HostMirrorSpace ; - typedef void array_layout ; - typedef MemoryTraits memory_traits ; - typedef void specialize ; + static_assert( + std::is_same::execution_space, + void>::value && + std::is_same::memory_space, + void>::value && + std::is_same::array_layout, + void>::value && + std::is_same::memory_traits, + void>::value, + "MemoryTrait is the final optional template argument for a View"); + + typedef void execution_space; + typedef void memory_space; + typedef void HostMirrorSpace; + typedef void array_layout; + typedef MemoryTraits memory_traits; + typedef void specialize; }; - -template< class DataType , class ... Properties > +template struct ViewTraits { -private: - + private: // Unpack the properties arguments - typedef ViewTraits< void , Properties ... > prop ; - - typedef typename - std::conditional< ! std::is_same< typename prop::execution_space , void >::value - , typename prop::execution_space - , Kokkos::DefaultExecutionSpace - >::type - ExecutionSpace ; - - typedef typename - std::conditional< ! std::is_same< typename prop::memory_space , void >::value - , typename prop::memory_space - , typename ExecutionSpace::memory_space - >::type - MemorySpace ; - - typedef typename - std::conditional< ! std::is_same< typename prop::array_layout , void >::value - , typename prop::array_layout - , typename ExecutionSpace::array_layout - >::type - ArrayLayout ; - - typedef typename - std::conditional - < ! std::is_same< typename prop::HostMirrorSpace , void >::value - , typename prop::HostMirrorSpace - , typename Kokkos::Impl::HostMirror< ExecutionSpace >::Space - >::type - HostMirrorSpace ; - - typedef typename - std::conditional< ! std::is_same< typename prop::memory_traits , void >::value - , typename prop::memory_traits - , typename Kokkos::MemoryManaged - >::type - MemoryTraits ; + typedef ViewTraits prop; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::execution_space, Kokkos::DefaultExecutionSpace>::type + ExecutionSpace; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::memory_space, typename ExecutionSpace::memory_space>::type + MemorySpace; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::array_layout, typename ExecutionSpace::array_layout>::type + ArrayLayout; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::HostMirrorSpace, + typename Kokkos::Impl::HostMirror::Space>::type + HostMirrorSpace; + + typedef typename std::conditional< + !std::is_same::value, + typename prop::memory_traits, typename Kokkos::MemoryManaged>::type + MemoryTraits; // Analyze data type's properties, // May be specialized based upon the layout and value type - typedef Kokkos::Impl::ViewDataAnalysis< DataType , ArrayLayout > data_analysis ; - -public: + typedef Kokkos::Impl::ViewDataAnalysis data_analysis; + public: //------------------------------------ // Data type traits: - typedef typename data_analysis::type data_type ; - typedef typename data_analysis::const_type const_data_type ; - typedef typename data_analysis::non_const_type non_const_data_type ; + typedef typename data_analysis::type data_type; + typedef typename data_analysis::const_type const_data_type; + typedef typename data_analysis::non_const_type non_const_data_type; //------------------------------------ // Compatible array of trivial type traits: - typedef typename data_analysis::scalar_array_type scalar_array_type ; - typedef typename data_analysis::const_scalar_array_type const_scalar_array_type ; - typedef typename data_analysis::non_const_scalar_array_type non_const_scalar_array_type ; + typedef typename data_analysis::scalar_array_type scalar_array_type; + typedef + typename data_analysis::const_scalar_array_type const_scalar_array_type; + typedef typename data_analysis::non_const_scalar_array_type + non_const_scalar_array_type; //------------------------------------ // Value type traits: - typedef typename data_analysis::value_type value_type ; - typedef typename data_analysis::const_value_type const_value_type ; - typedef typename data_analysis::non_const_value_type non_const_value_type ; + typedef typename data_analysis::value_type value_type; + typedef typename data_analysis::const_value_type const_value_type; + typedef typename data_analysis::non_const_value_type non_const_value_type; //------------------------------------ // Mapping traits: - typedef ArrayLayout array_layout ; - typedef typename data_analysis::dimension dimension ; + typedef ArrayLayout array_layout; + typedef typename data_analysis::dimension dimension; typedef typename std::conditional< - std::is_same::value - ,typename prop::specialize - ,typename data_analysis::specialize>::type - specialize ; /* mapping specialization tag */ + std::is_same::value, + typename prop::specialize, typename data_analysis::specialize>::type + specialize; /* mapping specialization tag */ - enum { rank = dimension::rank }; + enum { rank = dimension::rank }; enum { rank_dynamic = dimension::rank_dynamic }; //------------------------------------ // Execution space, memory space, memory access traits, and host mirror space. - typedef ExecutionSpace execution_space ; - typedef MemorySpace memory_space ; - typedef Kokkos::Device device_type ; - typedef MemoryTraits memory_traits ; - typedef HostMirrorSpace host_mirror_space ; + typedef ExecutionSpace execution_space; + typedef MemorySpace memory_space; + typedef Kokkos::Device device_type; + typedef MemoryTraits memory_traits; + typedef HostMirrorSpace host_mirror_space; - typedef typename MemorySpace::size_type size_type ; + typedef typename MemorySpace::size_type size_type; - enum { is_hostspace = std::is_same< MemorySpace , HostSpace >::value }; - enum { is_managed = MemoryTraits::is_unmanaged == 0 }; - enum { is_random_access = MemoryTraits::is_random_access == 1 }; + enum { is_hostspace = std::is_same::value }; + enum { is_managed = MemoryTraits::is_unmanaged == 0 }; + enum { is_random_access = MemoryTraits::is_random_access == 1 }; //------------------------------------ }; @@ -450,7 +417,8 @@ public: * * \section Kokkos_View_MT MemoryTraits discussion * - * \subsection Kokkos_View_MT_Interp MemoryTraits interpretation depends on Space + * \subsection Kokkos_View_MT_Interp MemoryTraits interpretation depends on + * Space * * Some \c MemoryTraits options may have different interpretations for * different \c Space types. For example, with the Cuda device, @@ -479,8 +447,8 @@ public: * } * \endcode */ -template< class DataType , class ... Properties > -class View ; +template +class View; } /* namespace Kokkos */ @@ -497,16 +465,15 @@ namespace Kokkos { namespace { -constexpr Kokkos::Impl::ALL_t - ALL = Kokkos::Impl::ALL_t(); +constexpr Kokkos::Impl::ALL_t ALL = Kokkos::Impl::ALL_t(); -constexpr Kokkos::Impl::WithoutInitializing_t - WithoutInitializing = Kokkos::Impl::WithoutInitializing_t(); +constexpr Kokkos::Impl::WithoutInitializing_t WithoutInitializing = + Kokkos::Impl::WithoutInitializing_t(); -constexpr Kokkos::Impl::AllowPadding_t - AllowPadding = Kokkos::Impl::AllowPadding_t(); +constexpr Kokkos::Impl::AllowPadding_t AllowPadding = + Kokkos::Impl::AllowPadding_t(); -} +} // namespace /** \brief Create View allocation parameter bundle from argument list. * @@ -515,39 +482,34 @@ constexpr Kokkos::Impl::AllowPadding_t * 2) memory space instance of the View::memory_space type * 3) execution space instance compatible with the View::memory_space * 4) Kokkos::WithoutInitializing to bypass initialization - * 4) Kokkos::AllowPadding to allow allocation to pad dimensions for memory alignment + * 4) Kokkos::AllowPadding to allow allocation to pad dimensions for memory + * alignment */ -template< class ... Args > -inline -Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > -view_alloc( Args const & ... args ) -{ - typedef - Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > - return_type ; +template +inline Impl::ViewCtorProp::type...> +view_alloc(Args const&... args) { + typedef Impl::ViewCtorProp::type...> + return_type; - static_assert( ! return_type::has_pointer - , "Cannot give pointer-to-memory for view allocation" ); + static_assert(!return_type::has_pointer, + "Cannot give pointer-to-memory for view allocation"); - return return_type( args... ); + return return_type(args...); } -template< class ... Args > +template KOKKOS_INLINE_FUNCTION -Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > -view_wrap( Args const & ... args ) -{ - typedef - Impl::ViewCtorProp< typename Impl::ViewCtorProp< void , Args >::type ... > - return_type ; + Impl::ViewCtorProp::type...> + view_wrap(Args const&... args) { + typedef Impl::ViewCtorProp::type...> + return_type; - static_assert( ! return_type::has_memory_space && - ! return_type::has_execution_space && - ! return_type::has_label && - return_type::has_pointer - , "Must only give pointer-to-memory for view wrapping" ); + static_assert(!return_type::has_memory_space && + !return_type::has_execution_space && + !return_type::has_label && return_type::has_pointer, + "Must only give pointer-to-memory for view wrapping"); - return return_type( args... ); + return return_type(args...); } } /* namespace Kokkos */ @@ -557,113 +519,120 @@ view_wrap( Args const & ... args ) namespace Kokkos { -template< class DataType , class ... Properties > -class View ; - -template< class > struct is_view : public std::false_type {}; - -template< class D, class ... P > -struct is_view< View > : public std::true_type {}; - -template< class D, class ... P > -struct is_view< const View > : public std::true_type {}; +template +class View; -template< class DataType , class ... Properties > -class View : public ViewTraits< DataType , Properties ... > { -private: +template +struct is_view : public std::false_type {}; - template< class , class ... > friend class View ; - template< class , class ... > friend class Kokkos::Impl::ViewMapping ; +template +struct is_view> : public std::true_type {}; -public: +template +struct is_view> : public std::true_type {}; - typedef ViewTraits< DataType , Properties ... > traits ; +template +class View : public ViewTraits { + private: + template + friend class View; + template + friend class Kokkos::Impl::ViewMapping; -private: + public: + typedef ViewTraits traits; - typedef Kokkos::Impl::ViewMapping< traits , typename traits::specialize > map_type ; - typedef Kokkos::Impl::SharedAllocationTracker track_type ; + private: + typedef Kokkos::Impl::ViewMapping + map_type; + typedef Kokkos::Impl::SharedAllocationTracker track_type; - track_type m_track ; - map_type m_map ; - -public: + track_type m_track; + map_type m_map; + public: //---------------------------------------- /** \brief Compatible view of array of scalar types */ - typedef View< typename traits::scalar_array_type , - typename traits::array_layout , - typename traits::device_type , - typename traits::memory_traits > - array_type ; + typedef View + array_type; /** \brief Compatible view of const data type */ - typedef View< typename traits::const_data_type , - typename traits::array_layout , - typename traits::device_type , - typename traits::memory_traits > - const_type ; + typedef View + const_type; /** \brief Compatible view of non-const data type */ - typedef View< typename traits::non_const_data_type , - typename traits::array_layout , - typename traits::device_type , - typename traits::memory_traits > - non_const_type ; + typedef View + non_const_type; /** \brief Compatible HostMirror view */ - typedef View< typename traits::non_const_data_type , - typename traits::array_layout , - typename traits::host_mirror_space > - HostMirror ; + typedef View> + HostMirror; /** \brief Compatible HostMirror view */ - typedef View< typename traits::non_const_data_type , - typename traits::array_layout , - typename traits::host_mirror_space > - host_mirror_type ; + typedef View + host_mirror_type; /** \brief Unified types */ - typedef typename Impl::ViewUniformType::type uniform_type; - typedef typename Impl::ViewUniformType::const_type uniform_const_type; - typedef typename Impl::ViewUniformType::runtime_type uniform_runtime_type; - typedef typename Impl::ViewUniformType::runtime_const_type uniform_runtime_const_type; - typedef typename Impl::ViewUniformType::nomemspace_type uniform_nomemspace_type; - typedef typename Impl::ViewUniformType::const_nomemspace_type uniform_const_nomemspace_type; - typedef typename Impl::ViewUniformType::runtime_nomemspace_type uniform_runtime_nomemspace_type; - typedef typename Impl::ViewUniformType::runtime_const_nomemspace_type uniform_runtime_const_nomemspace_type; + typedef typename Impl::ViewUniformType::type uniform_type; + typedef + typename Impl::ViewUniformType::const_type uniform_const_type; + typedef typename Impl::ViewUniformType::runtime_type + uniform_runtime_type; + typedef typename Impl::ViewUniformType::runtime_const_type + uniform_runtime_const_type; + typedef typename Impl::ViewUniformType::nomemspace_type + uniform_nomemspace_type; + typedef typename Impl::ViewUniformType::const_nomemspace_type + uniform_const_nomemspace_type; + typedef typename Impl::ViewUniformType::runtime_nomemspace_type + uniform_runtime_nomemspace_type; + typedef typename Impl::ViewUniformType::runtime_const_nomemspace_type + uniform_runtime_const_nomemspace_type; //---------------------------------------- // Domain rank and extents enum { Rank = map_type::Rank }; - /** \brief rank() to be implemented - */ - //KOKKOS_INLINE_FUNCTION - //static - //constexpr unsigned rank() { return map_type::Rank; } + /** \brief rank() to be implemented + */ + // KOKKOS_INLINE_FUNCTION + // static + // constexpr unsigned rank() { return map_type::Rank; } - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - extent( const iType & r ) const noexcept - { return m_map.extent(r); } + typename std::enable_if::value, size_t>::type + extent(const iType& r) const noexcept { + return m_map.extent(r); + } - static KOKKOS_INLINE_FUNCTION constexpr - size_t - static_extent( const unsigned r ) noexcept - { return map_type::static_extent(r); } + static KOKKOS_INLINE_FUNCTION constexpr size_t static_extent( + const unsigned r) noexcept { + return map_type::static_extent(r); + } - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , int >::type - extent_int( const iType & r ) const noexcept - { return static_cast(m_map.extent(r)); } + typename std::enable_if::value, int>::type + extent_int(const iType& r) const noexcept { + return static_cast(m_map.extent(r)); + } - KOKKOS_INLINE_FUNCTION constexpr - typename traits::array_layout layout() const - { return m_map.layout(); } + KOKKOS_INLINE_FUNCTION constexpr typename traits::array_layout layout() + const { + return m_map.layout(); + } //---------------------------------------- /* Deprecate all 'dimension' functions in favor of @@ -672,80 +641,134 @@ public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< typename iType > + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - dimension( const iType & r ) const { return extent( r ); } - - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { return m_map.dimension_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { return m_map.dimension_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { return m_map.dimension_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { return m_map.dimension_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { return m_map.dimension_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { return m_map.dimension_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { return m_map.dimension_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { return m_map.dimension_7(); } + typename std::enable_if::value, size_t>::type + dimension(const iType& r) const { + return extent(r); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_0() const { + return m_map.dimension_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_1() const { + return m_map.dimension_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_2() const { + return m_map.dimension_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_3() const { + return m_map.dimension_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_4() const { + return m_map.dimension_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_5() const { + return m_map.dimension_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_6() const { + return m_map.dimension_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t dimension_7() const { + return m_map.dimension_7(); + } #endif //---------------------------------------- - KOKKOS_INLINE_FUNCTION constexpr size_t size() const { return m_map.dimension_0() * - m_map.dimension_1() * - m_map.dimension_2() * - m_map.dimension_3() * - m_map.dimension_4() * - m_map.dimension_5() * - m_map.dimension_6() * - m_map.dimension_7(); } - - KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { return m_map.stride_0(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { return m_map.stride_1(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { return m_map.stride_2(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { return m_map.stride_3(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { return m_map.stride_4(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { return m_map.stride_5(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { return m_map.stride_6(); } - KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { return m_map.stride_7(); } - - template< typename iType > + KOKKOS_INLINE_FUNCTION constexpr size_t size() const { + return m_map.dimension_0() * m_map.dimension_1() * m_map.dimension_2() * + m_map.dimension_3() * m_map.dimension_4() * m_map.dimension_5() * + m_map.dimension_6() * m_map.dimension_7(); + } + + KOKKOS_INLINE_FUNCTION constexpr size_t stride_0() const { + return m_map.stride_0(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_1() const { + return m_map.stride_1(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_2() const { + return m_map.stride_2(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_3() const { + return m_map.stride_3(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_4() const { + return m_map.stride_4(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_5() const { + return m_map.stride_5(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_6() const { + return m_map.stride_6(); + } + KOKKOS_INLINE_FUNCTION constexpr size_t stride_7() const { + return m_map.stride_7(); + } + + template KOKKOS_INLINE_FUNCTION constexpr - typename std::enable_if< std::is_integral::value , size_t >::type - stride(iType r) const { - return (r == 0 ? m_map.stride_0() : - (r == 1 ? m_map.stride_1() : - (r == 2 ? m_map.stride_2() : - (r == 3 ? m_map.stride_3() : - (r == 4 ? m_map.stride_4() : - (r == 5 ? m_map.stride_5() : - (r == 6 ? m_map.stride_6() : - m_map.stride_7()))))))); + typename std::enable_if::value, size_t>::type + stride(iType r) const { + return ( + r == 0 + ? m_map.stride_0() + : (r == 1 + ? m_map.stride_1() + : (r == 2 + ? m_map.stride_2() + : (r == 3 + ? m_map.stride_3() + : (r == 4 + ? m_map.stride_4() + : (r == 5 + ? m_map.stride_5() + : (r == 6 + ? m_map.stride_6() + : m_map.stride_7()))))))); } - template< typename iType > - KOKKOS_INLINE_FUNCTION void stride( iType * const s ) const { m_map.stride(s); } + template + KOKKOS_INLINE_FUNCTION void stride(iType* const s) const { + m_map.stride(s); + } //---------------------------------------- // Range span is the span which contains all members. - typedef typename map_type::reference_type reference_type ; - typedef typename map_type::pointer_type pointer_type ; + typedef typename map_type::reference_type reference_type; + typedef typename map_type::pointer_type pointer_type; - enum { reference_type_is_lvalue_reference = std::is_lvalue_reference< reference_type >::value }; + enum { + reference_type_is_lvalue_reference = + std::is_lvalue_reference::value + }; KOKKOS_INLINE_FUNCTION constexpr size_t span() const { return m_map.span(); } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span()' instead - KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { return m_map.span(); } + KOKKOS_INLINE_FUNCTION constexpr size_t capacity() const { + return m_map.span(); + } #endif - KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { return m_map.span_is_contiguous(); } - KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION bool span_is_contiguous() const { + return m_map.span_is_contiguous(); + } + KOKKOS_INLINE_FUNCTION constexpr pointer_type data() const { + return m_map.data(); + } #ifdef KOKKOS_ENABLE_DEPRECATED_CODE // Deprecated, use 'span_is_contigous()' instead - KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { return m_map.span_is_contiguous(); } + KOKKOS_INLINE_FUNCTION constexpr bool is_contiguous() const { + return m_map.span_is_contiguous(); + } // Deprecated, use 'data()' instead - KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { return m_map.data(); } + KOKKOS_INLINE_FUNCTION constexpr pointer_type ptr_on_device() const { + return m_map.data(); + } #endif //---------------------------------------- @@ -753,1215 +776,946 @@ public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - implementation_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + implementation_map() const { + return m_map; + } #endif KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::ViewMapping< traits , typename traits::specialize > & - impl_map() const { return m_map ; } + const Kokkos::Impl::ViewMapping& + impl_map() const { + return m_map; + } KOKKOS_INLINE_FUNCTION - const Kokkos::Impl::SharedAllocationTracker & - impl_track() const { return m_track ; } + const Kokkos::Impl::SharedAllocationTracker& impl_track() const { + return m_track; + } //---------------------------------------- -private: - + private: enum { - is_layout_left = std::is_same< typename traits::array_layout - , Kokkos::LayoutLeft >::value , + is_layout_left = + std::is_same::value, - is_layout_right = std::is_same< typename traits::array_layout - , Kokkos::LayoutRight >::value , + is_layout_right = + std::is_same::value, - is_layout_stride = std::is_same< typename traits::array_layout - , Kokkos::LayoutStride >::value , + is_layout_stride = std::is_same::value, - is_default_map = - std::is_same< typename traits::specialize , void >::value && - ( is_layout_left || is_layout_right || is_layout_stride ) + is_default_map = std::is_same::value && + (is_layout_left || is_layout_right || is_layout_stride) }; - template< class Space , bool = Kokkos::Impl::MemorySpaceAccess< Space , typename traits::memory_space >::accessible > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() {} }; + template ::accessible> + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() {} + }; - template< class Space > struct verify_space - { KOKKOS_FORCEINLINE_FUNCTION static void check() - { Kokkos::abort("Kokkos::View ERROR: attempt to access inaccessible memory space"); }; + template + struct verify_space { + KOKKOS_FORCEINLINE_FUNCTION static void check() { + Kokkos::abort( + "Kokkos::View ERROR: attempt to access inaccessible memory space"); }; + }; -#if defined( KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK ) +#if defined(KOKKOS_ENABLE_DEBUG_BOUNDS_CHECK) -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - View::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); \ - Kokkos::Impl::view_verify_operator_bounds< typename traits::memory_space > ARG ; +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + View::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); \ + Kokkos::Impl::view_verify_operator_bounds ARG; #else -#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( ARG ) \ - View::template verify_space< Kokkos::Impl::ActiveExecutionMemorySpace >::check(); +#define KOKKOS_IMPL_VIEW_OPERATOR_VERIFY(ARG) \ + View::template verify_space< \ + Kokkos::Impl::ActiveExecutionMemorySpace>::check(); #endif -public: + public: #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - template< class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if<( Kokkos::Impl::are_integral::value - && ( 0 == Rank ) - ), reference_type >::type - operator()( Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,args...) ) - return m_map.reference(); - } - - template< typename I0 - , class ... Args> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0, - Args ... args) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.reference(i0); - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - //------------------------------ - // Rank 1 operator[] - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.reference(i0); - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.reference(i0,i1); - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_dim.N0 * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_stride * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_dim.N1 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_stride * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 * m_map.m_impl_offset.m_stride.S0 + - i1 * m_map.m_impl_offset.m_stride.S1 ]; - } - - //------------------------------ - // Rank 3 - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2) ]; - } - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.reference(i0,i1,i2); - } - - //------------------------------ - // Rank 4 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.reference(i0,i1,i2,i3); - } - - //------------------------------ - // Rank 5 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.reference(i0,i1,i2,i3,i4); - } - - //------------------------------ - // Rank 6 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } - - //------------------------------ - // Rank 7 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } - - //------------------------------ - // Rank 8 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6,i7) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6,i7); - } - - - #else + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (0 == Rank)), + reference_type>::type + operator()(Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, args...)) + return m_map.reference(); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.reference(i0); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator()(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator()(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + + //------------------------------ + // Rank 1 operator[] + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.reference(i0); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.reference(i0, i1); + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_dim.N0 * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_stride * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_dim.N1 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_stride * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_stride), + reference_type>::type + operator()(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 * m_map.m_impl_offset.m_stride.S0 + + i1 * m_map.m_impl_offset.m_stride.S1]; + } + + //------------------------------ + // Rank 3 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.reference(i0, i1, i2); + } + + //------------------------------ + // Rank 4 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.reference(i0, i1, i2, i3); + } + + //------------------------------ + // Rank 5 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.reference(i0, i1, i2, i3, i4); + } + + //------------------------------ + // Rank 6 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } + + //------------------------------ + // Rank 7 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } + + //------------------------------ + // Rank 8 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map + .m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6, i7)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6, i7); + } + +#else //------------------------------ // Rank 0 operator() - KOKKOS_FORCEINLINE_FUNCTION - reference_type - operator()() const - { - return m_map.reference(); - } + KOKKOS_FORCEINLINE_FUNCTION + reference_type operator()() const { return m_map.reference(); } //------------------------------ // Rank 1 operator() + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.reference(i0); + } - template< typename I0> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.reference(i0); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator()(const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[i0]; + } - template< typename I0> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator()(const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + //------------------------------ + // Rank 1 operator[] - template< typename I0 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.reference(i0); + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator[](const I0& i0) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + //------------------------------ - // Rank 1 operator[] - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.reference(i0); - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator[]( const I0 & i0 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - - //------------------------------ // Rank 2 - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.reference(i0,i1); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.reference(i0, i1); + } - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_dim.N0 * i1 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_left && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_dim.N0 * i1]; + } - template< typename I0 , typename I1> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_stride * i1 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_left && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_stride * i1]; + } - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_dim.N1 * i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_right && (traits::rank_dynamic == 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_dim.N1 * i0]; + } - template< typename I0 , typename I1 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_stride * i0 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_right && (traits::rank_dynamic != 0)), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_stride * i0]; + } - template< typename I0 , typename I1> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1) ) - return m_map.m_impl_handle[ i0 * m_map.m_impl_offset.m_stride.S0 + - i1 * m_map.m_impl_offset.m_stride.S1 ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (2 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + operator()(const I0& i0, const I1& i1) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1)) + return m_map.m_impl_handle[i0 * m_map.m_impl_offset.m_stride.S0 + + i1 * m_map.m_impl_offset.m_stride.S1]; + } //------------------------------ // Rank 3 - template< typename I0 , typename I1 , typename I2 > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2) ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (3 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2)]; + } - template< typename I0 , typename I1 , typename I2> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2) ) - return m_map.reference(i0,i1,i2); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (3 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2)) + return m_map.reference(i0, i1, i2); + } //------------------------------ // Rank 4 - template< typename I0 , typename I1 , typename I2 , typename I3> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (4 == Rank) && + is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3) ) - return m_map.reference(i0,i1,i2,i3); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (4 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3)) + return m_map.reference(i0, i1, i2, i3); + } //------------------------------ // Rank 5 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (5 == Rank) && + is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4) ) - return m_map.reference(i0,i1,i2,i3,i4); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (5 == Rank) && + !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4)) + return m_map.reference(i0, i1, i2, i3, i4); + } //------------------------------ // Rank 6 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, i4, i5)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } //------------------------------ // Rank 7 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6) ]; - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6)]; + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } //------------------------------ // Rank 8 - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 > + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7)) + return m_map + .m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6, i7)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && !is_default_map), + reference_type>::type + operator()(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + const I4& i4, const I5& i5, const I6& i6, const I7& i7) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6, i7); + } + +#endif + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6,i7) ]; - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (0 == Rank)), + reference_type>::type + access(Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, args...)) + return m_map.reference(); + } - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7> + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && ! is_default_map - ), reference_type >::type - operator()( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6,i7); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.reference(i0); + } -#endif - template< class ... Args > + template KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if<( Kokkos::Impl::are_integral::value - && ( 0 == Rank ) - ), reference_type >::type - access( Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,args...) ) - return m_map.reference(); - } + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + !is_layout_stride), + reference_type>::type + access(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION + typename std::enable_if<(Kokkos::Impl::are_integral::value && + (1 == Rank) && is_default_map && + is_layout_stride), + reference_type>::type + access(const I0& i0, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset.m_stride.S0 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.reference(i0, i1); + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic == 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_dim.N0 * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_left && (traits::rank_dynamic != 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 + m_map.m_impl_offset.m_stride * i1]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic == 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_dim.N1 * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_right && (traits::rank_dynamic != 0)), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i1 + m_map.m_impl_offset.m_stride * i0]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (2 == Rank) && + is_default_map && is_layout_stride), + reference_type>::type + access(const I0& i0, const I1& i1, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, args...)) + return m_map.m_impl_handle[i0 * m_map.m_impl_offset.m_stride.S0 + + i1 * m_map.m_impl_offset.m_stride.S1]; + } + + //------------------------------ + // Rank 3 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && (3 == Rank) && + !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, args...)) + return m_map.reference(i0, i1, i2); + } + + //------------------------------ + // Rank 4 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (4 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY((m_track, m_map, i0, i1, i2, i3, args...)) + return m_map.reference(i0, i1, i2, i3); + } + + //------------------------------ + // Rank 5 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (5 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, args...)) + return m_map.reference(i0, i1, i2, i3, i4); + } + + //------------------------------ + // Rank 6 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (6 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5); + } + + //------------------------------ + // Rank 7 + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6)]; + } - template< typename I0 - , class ... Args> - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0, - Args ... args) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.reference(i0); - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && ! is_layout_stride - ), reference_type >::type - access( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ i0 ]; - } - - template< typename I0 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 1 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - access( const I0 & i0 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset.m_stride.S0 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.reference(i0,i1); - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_dim.N0 * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_left && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 + m_map.m_impl_offset.m_stride * i1 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic == 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_dim.N1 * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_right && ( traits::rank_dynamic != 0 ) - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i1 + m_map.m_impl_offset.m_stride * i0 ]; - } - - template< typename I0 , typename I1 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 2 == Rank ) - && is_default_map - && is_layout_stride - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,args...) ) - return m_map.m_impl_handle[ i0 * m_map.m_impl_offset.m_stride.S0 + - i1 * m_map.m_impl_offset.m_stride.S1 ]; - } - - //------------------------------ - // Rank 3 - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2) ]; - } - - template< typename I0 , typename I1 , typename I2 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 3 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,args...) ) - return m_map.reference(i0,i1,i2); - } - - //------------------------------ - // Rank 4 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 4 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,args...) ) - return m_map.reference(i0,i1,i2,i3); - } - - //------------------------------ - // Rank 5 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 5 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,args...) ) - return m_map.reference(i0,i1,i2,i3,i4); - } - - //------------------------------ - // Rank 6 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 6 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5); - } - - //------------------------------ - // Rank 7 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 7 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6); - } - - //------------------------------ - // Rank 8 - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.m_impl_handle[ m_map.m_impl_offset(i0,i1,i2,i3,i4,i5,i6,i7) ]; - } - - template< typename I0 , typename I1 , typename I2 , typename I3 - , typename I4 , typename I5 , typename I6 , typename I7 - , class ... Args > - KOKKOS_FORCEINLINE_FUNCTION - typename std::enable_if< - ( Kokkos::Impl::are_integral::value - && ( 8 == Rank ) - && ! is_default_map - ), reference_type >::type - access( const I0 & i0 , const I1 & i1 , const I2 & i2 , const I3 & i3 - , const I4 & i4 , const I5 & i5 , const I6 & i6 , const I7 & i7 - , Args ... args ) const - { - KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( (m_track,m_map,i0,i1,i2,i3,i4,i5,i6,i7,args...) ) - return m_map.reference(i0,i1,i2,i3,i4,i5,i6,i7); - } + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (7 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6); + } + + //------------------------------ + // Rank 8 + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, const I7& i7, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map + .m_impl_handle[m_map.m_impl_offset(i0, i1, i2, i3, i4, i5, i6, i7)]; + } + + template + KOKKOS_FORCEINLINE_FUNCTION typename std::enable_if< + (Kokkos::Impl::are_integral::value && + (8 == Rank) && !is_default_map), + reference_type>::type + access(const I0& i0, const I1& i1, const I2& i2, const I3& i3, const I4& i4, + const I5& i5, const I6& i6, const I7& i7, Args... args) const { + KOKKOS_IMPL_VIEW_OPERATOR_VERIFY( + (m_track, m_map, i0, i1, i2, i3, i4, i5, i6, i7, args...)) + return m_map.reference(i0, i1, i2, i3, i4, i5, i6, i7); + } #undef KOKKOS_IMPL_VIEW_OPERATOR_VERIFY @@ -1975,546 +1729,522 @@ public: View() : m_track(), m_map() {} KOKKOS_INLINE_FUNCTION - View( const View & rhs ) : m_track( rhs.m_track, traits::is_managed ), m_map( rhs.m_map ) {} + View(const View& rhs) + : m_track(rhs.m_track, traits::is_managed), m_map(rhs.m_map) {} KOKKOS_INLINE_FUNCTION - View( View && rhs ) : m_track( std::move(rhs.m_track) ), m_map( std::move(rhs.m_map) ) {} + View(View&& rhs) + : m_track(std::move(rhs.m_track)), m_map(std::move(rhs.m_map)) {} KOKKOS_INLINE_FUNCTION - View & operator = ( const View & rhs ) { m_track = rhs.m_track ; m_map = rhs.m_map ; return *this ; } + View& operator=(const View& rhs) { + m_track = rhs.m_track; + m_map = rhs.m_map; + return *this; + } KOKKOS_INLINE_FUNCTION - View & operator = ( View && rhs ) { m_track = std::move(rhs.m_track) ; m_map = std::move(rhs.m_map) ; return *this ; } - - + View& operator=(View&& rhs) { + m_track = std::move(rhs.m_track); + m_map = std::move(rhs.m_map); + return *this; + } //---------------------------------------- // Compatible view copy constructor and assignment // may assign unmanaged from managed. - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - View( const View & rhs, - typename std::enable_if::traits , typename traits::specialize >::is_assignable_data_type>::type* = 0 - ) - : m_track( rhs.m_track , traits::is_managed ) - , m_map() - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View copy construction" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - } + template + KOKKOS_INLINE_FUNCTION View( + const View& rhs, + typename std::enable_if::traits, + typename traits::specialize>::is_assignable_data_type>::type* = 0) + : m_track(rhs.m_track, traits::is_managed), m_map() { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, + "Incompatible View copy construction"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + } - template< class RT , class ... RP > - KOKKOS_INLINE_FUNCTION - typename std::enable_if::traits , typename traits::specialize >::is_assignable_data_type, - View>::type & operator = ( const View & rhs ) - { - typedef typename View::traits SrcTraits ; - typedef Kokkos::Impl::ViewMapping< traits , SrcTraits , typename traits::specialize > Mapping ; - static_assert( Mapping::is_assignable , "Incompatible View copy assignment" ); - Mapping::assign( m_map , rhs.m_map , rhs.m_track ); - m_track.assign( rhs.m_track , traits::is_managed ); - return *this ; - } + template + KOKKOS_INLINE_FUNCTION typename std::enable_if< + Kokkos::Impl::ViewMapping< + traits, typename View::traits, + typename traits::specialize>::is_assignable_data_type, + View>::type& + operator=(const View& rhs) { + typedef typename View::traits SrcTraits; + typedef Kokkos::Impl::ViewMapping + Mapping; + static_assert(Mapping::is_assignable, "Incompatible View copy assignment"); + Mapping::assign(m_map, rhs.m_map, rhs.m_track); + m_track.assign(rhs.m_track, traits::is_managed); + return *this; + } //---------------------------------------- // Compatible subview constructor // may assign unmanaged from managed. - template< class RT , class ... RP , class Arg0 , class ... Args > - KOKKOS_INLINE_FUNCTION - View( const View< RT , RP... > & src_view - , const Arg0 arg0 , Args ... args ) - : m_track( src_view.m_track , traits::is_managed ) - , m_map() - { - typedef View< RT , RP... > SrcType ; + template + KOKKOS_INLINE_FUNCTION View(const View& src_view, const Arg0 arg0, + Args... args) + : m_track(src_view.m_track, traits::is_managed), m_map() { + typedef View SrcType; - typedef Kokkos::Impl::ViewMapping - < void /* deduce destination view type from source view traits */ - , typename SrcType::traits - , Arg0 , Args... > Mapping ; + typedef Kokkos::Impl::ViewMapping + Mapping; - typedef typename Mapping::type DstType ; + typedef typename Mapping::type DstType; - static_assert( Kokkos::Impl::ViewMapping< traits , typename DstType::traits , typename traits::specialize >::is_assignable - , "Subview construction requires compatible view and subview arguments" ); + static_assert( + Kokkos::Impl::ViewMapping::is_assignable, + "Subview construction requires compatible view and subview arguments"); - Mapping::assign( m_map, src_view.m_map, arg0 , args... ); - } + Mapping::assign(m_map, src_view.m_map, arg0, args...); + } //---------------------------------------- // Allocation tracking properties KOKKOS_INLINE_FUNCTION - int use_count() const - { return m_track.use_count(); } + int use_count() const { return m_track.use_count(); } - inline - const std::string label() const - { return m_track.template get_label< typename traits::memory_space >(); } + inline const std::string label() const { + return m_track.template get_label(); + } //---------------------------------------- // Allocation according to allocation properties and array layout - template< class ... P > - explicit inline - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() - , m_map() - { - // Append layout and spaces if not input - typedef Impl::ViewCtorProp< P ... > alloc_prop_input ; - - // use 'std::integral_constant' for non-types - // to avoid duplicate class error. - typedef Impl::ViewCtorProp - < P ... - , typename std::conditional - < alloc_prop_input::has_label - , std::integral_constant - , typename std::string - >::type - , typename std::conditional - < alloc_prop_input::has_memory_space - , std::integral_constant - , typename traits::device_type::memory_space - >::type - , typename std::conditional - < alloc_prop_input::has_execution_space - , std::integral_constant - , typename traits::device_type::execution_space - >::type - > alloc_prop ; - - static_assert( traits::is_managed - , "View allocation constructor requires managed memory" ); - - if ( alloc_prop::initialize && + template + explicit inline View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track(), m_map() { + // Append layout and spaces if not input + typedef Impl::ViewCtorProp alloc_prop_input; + + // use 'std::integral_constant' for non-types + // to avoid duplicate class error. + typedef Impl::ViewCtorProp< + P..., + typename std::conditional, + typename std::string>::type, + typename std::conditional< + alloc_prop_input::has_memory_space, + std::integral_constant, + typename traits::device_type::memory_space>::type, + typename std::conditional< + alloc_prop_input::has_execution_space, + std::integral_constant, + typename traits::device_type::execution_space>::type> + alloc_prop; + + static_assert(traits::is_managed, + "View allocation constructor requires managed memory"); + + if (alloc_prop::initialize && #ifdef KOKKOS_ENABLE_DEPRECATED_CODE - ! alloc_prop::execution_space::is_initialized() + !alloc_prop::execution_space::is_initialized() #else - ! alloc_prop::execution_space::impl_is_initialized() + !alloc_prop::execution_space::impl_is_initialized() #endif - ) { - // If initializing view data then - // the execution space must be initialized. - Kokkos::Impl::throw_runtime_exception("Constructing View and initializing data with uninitialized execution space"); - } + ) { + // If initializing view data then + // the execution space must be initialized. + Kokkos::Impl::throw_runtime_exception( + "Constructing View and initializing data with uninitialized " + "execution space"); + } - // Copy the input allocation properties with possibly defaulted properties - alloc_prop prop_copy( arg_prop ); + // Copy the input allocation properties with possibly defaulted properties + alloc_prop prop_copy(arg_prop); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - // If allocating in CudaUVMSpace must fence before and after - // the allocation to protect against possible concurrent access - // on the CPU and the GPU. - // Fence using the trait's executon space (which will be Kokkos::Cuda) - // to avoid incomplete type errors from usng Kokkos::Cuda directly. - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } +#if defined(KOKKOS_ENABLE_CUDA) + // If allocating in CudaUVMSpace must fence before and after + // the allocation to protect against possible concurrent access + // on the CPU and the GPU. + // Fence using the trait's executon space (which will be Kokkos::Cuda) + // to avoid incomplete type errors from usng Kokkos::Cuda directly. + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); + } #endif -//------------------------------------------------------------ + //------------------------------------------------------------ - Kokkos::Impl::SharedAllocationRecord<> * - record = m_map.allocate_shared( prop_copy , arg_layout ); + Kokkos::Impl::SharedAllocationRecord<>* record = + m_map.allocate_shared(prop_copy, arg_layout); //------------------------------------------------------------ -#if defined( KOKKOS_ENABLE_CUDA ) - if ( std::is_same< Kokkos::CudaUVMSpace , typename traits::device_type::memory_space >::value ) { - typename traits::device_type::memory_space::execution_space().fence(); - } +#if defined(KOKKOS_ENABLE_CUDA) + if (std::is_same::value) { + typename traits::device_type::memory_space::execution_space().fence(); + } #endif -//------------------------------------------------------------ + //------------------------------------------------------------ - // Setup and initialization complete, start tracking - m_track.assign_allocated_record_to_uninitialized( record ); - } + // Setup and initialization complete, start tracking + m_track.assign_allocated_record_to_uninitialized(record); + } KOKKOS_INLINE_FUNCTION - void assign_data( pointer_type arg_data ) - { - m_track.clear(); - m_map.assign_data( arg_data ); - } + void assign_data(pointer_type arg_data) { + m_track.clear(); + m_map.assign_data(arg_data); + } // Wrap memory according to properties and array layout - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Impl::ViewCtorProp< P... >::has_pointer - , typename traits::array_layout - >::type const & arg_layout - ) - : m_track() // No memory tracking - , m_map( arg_prop , arg_layout ) - { - static_assert( - std::is_same< pointer_type - , typename Impl::ViewCtorProp< P... >::pointer_type - >::value , - "Constructing View to wrap user memory must supply matching pointer type" ); - } + template + explicit KOKKOS_INLINE_FUNCTION View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + typename traits::array_layout>::type const& + arg_layout) + : m_track() // No memory tracking + , + m_map(arg_prop, arg_layout) { + static_assert( + std::is_same::pointer_type>::value, + "Constructing View to wrap user memory must supply matching pointer " + "type"); + } // Simple dimension-only layout - template< class ... P > - explicit inline - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< ! Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - ) - : View( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 - , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - { + template + explicit inline View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = + KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) + : View(arg_prop, + typename traits::array_layout(arg_N0, arg_N1, arg_N2, arg_N3, + arg_N4, arg_N5, arg_N6, arg_N7)) { #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST - Impl::runtime_check_rank_host(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7, label()); + Impl::runtime_check_rank_host( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7, label()); #else - Impl::runtime_check_rank_device(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7); + Impl::runtime_check_rank_device( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7); #endif + } - } - - template< class ... P > - explicit KOKKOS_INLINE_FUNCTION - View( const Impl::ViewCtorProp< P ... > & arg_prop - , typename std::enable_if< Impl::ViewCtorProp< P... >::has_pointer - , size_t - >::type const arg_N0 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - , const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG - ) - : View( arg_prop - , typename traits::array_layout - ( arg_N0 , arg_N1 , arg_N2 , arg_N3 - , arg_N4 , arg_N5 , arg_N6 , arg_N7 ) - ) - { + template + explicit KOKKOS_INLINE_FUNCTION View( + const Impl::ViewCtorProp& arg_prop, + typename std::enable_if::has_pointer, + size_t>::type const arg_N0 = + KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N1 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N2 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N3 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N4 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N5 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N6 = KOKKOS_IMPL_CTOR_DEFAULT_ARG, + const size_t arg_N7 = KOKKOS_IMPL_CTOR_DEFAULT_ARG) + : View(arg_prop, + typename traits::array_layout(arg_N0, arg_N1, arg_N2, arg_N3, + arg_N4, arg_N5, arg_N6, arg_N7)) { #ifdef KOKKOS_ACTIVE_EXECUTION_MEMORY_SPACE_HOST - Impl::runtime_check_rank_host(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7, label()); + Impl::runtime_check_rank_host( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7, label()); #else - Impl::runtime_check_rank_device(traits::rank_dynamic, std::is_same::value, arg_N0, arg_N1, arg_N2, arg_N3, - arg_N4, arg_N5, arg_N6, arg_N7); + Impl::runtime_check_rank_device( + traits::rank_dynamic, + std::is_same::value, arg_N0, arg_N1, + arg_N2, arg_N3, arg_N4, arg_N5, arg_N6, arg_N7); #endif - - } + } // Allocate with label and layout - template< typename Label > - explicit inline - View( const Label & arg_label - , typename std::enable_if< - Kokkos::Impl::is_view_label